When having two classes that has the same name, but in different namespaces, ServiceStacks OrmLite is unable to distinguish between the two. For example:
Type type = typeof(FirstNameSpace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates table "basemodel"
}
type = typeof(SecondNamespace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates nothing as there already is a table 'basemodel', even though its a completely different object/class
}
Is there a general, clean way to make sure that this is resolved?
It is not ideal to be forced to name classes uniquely; a part of the namespaces in .NET is to group and categorize different classes. Also, there might be third-party assemblies with the same class names, that is not available to change for you.
Is there a way to handle this?
OrmLite uses the name of the Type for the table name so you can’t use 2 different Types with the same name.
You will need to either rename one of the Types to avoid the collision or use the [Alias(“UseTableName”)] attribute to tell one of the Types to use a different RDBMS Table name.
Related
So I'm trying to refactor rewrite my app in a DDD way. This is a simple app with 3 classes :
Configuration(name)
Environment(name)
Property(key)
I use it to view and edit configuration files per environment. One Configuration can be viewed as a table with Property as row and Environment as column.
At this time, the Configuration is an entity and Environment and Property are value objects. But now I jave to implement the us ecase to set a Value to a Property for a given Environment. My first idea was this one :
class Configuration(name) {
environments = SetOf[Environment]
properties = SetOf[Property]
setValue(property, environment, value) {
knowEnv = environments.get(environment)
knowEnv.setValue(property, value)
}
}
class Environment(name) {
properties = MapOf[Property, Value]
setValue(property, value) {
properties[property] = value
}
}
But doing so will change my Environment from a value object to an entity. So I started to think (too much) and have trouble to find the "best" solution. That's why I came here to ask you, experts, how would you implement this use case.
Thanks
From what you've posted it does sound as though each Environment is a unique thing with an identity. I'm guessing your Environments are probably platforms or development environments? So it probably should be an entity.
It does sound as though your Environment could be edited, used, created, etc. independently of anything else. In this case it probably shouldn't exist as part of another aggregate, so it should be it's own aggregate root (even if it's just a single entity). Therefore it would have it's own repository. This is a point that isn't blatantly obvious in the Evans DDD book, but an entity on it's own, is considered an aggregate root (made up of just one object).
If you wish to reference an Environment from another aggregate root, you would reference it by its unique id (not as a object reference). You would then need another technique/method to retrieve these Environments.
This might seem to fly in the face of the old data-centric dogma, but you can do all sorts of things, like data caching your Environments (as there's probably a limited amount and they probably change infrequently) or employ CQRS.
Given the discussion and comments received on this questions I decided to keep the Environment immutable as value object. Setting a property value will then produce a new Environment :
class Configuration(name) {
environments = SetOf[Environment]
properties = SetOf[Property]
setValue(property, environment, value) {
knowEnv = environments.get(environment)
updatedEnv = knowEnv.setValue(property, value)
environments.replace(knowEnv, updatedEnv)
}
}
class Environment(name) {
properties = MapOf[Property, Value]
setValue(property, value) {
copy = new Environment(name)
copy.properties = properties
copy.properties[property] = value
return copy
}
}
It is simple to use and acceptable for our use cases.
After spending a year working with the Microsoft.Xrm.Sdk namespace, I just discovered yesterday the Entity.FormattedValues property contains the text value for Entity specific (ie Local) Option Set texts.
The reason I didn't discover it before, is there is no early bound method of getting the value. i.e. entity.new_myOptionSet is of type OptionSetValue which only contains the int value. You have to call entity.FormattedValues["new_myoptionset"] to get the string text value of the OptionSetValue.
Therefore, I'd like to get the crmsrvcutil to auto-generate a text property for local option sets. i.e. Along with Entity.new_myOptionSet being generated as it currently does, Entity.new_myOptionSetText would be generated as well.
I've looked into the Microsoft.Crm.Services.Utility.ICodeGenerationService, but that looks like it is mostly for specifying what CodeGenerationType something should be...
Is there a way supported way using CrmServiceUtil to add these properties, or am I better off writing a custom app that I can run that can generate these properties as a partial class to the auto-generated ones?
Edit - Example of the code that I would like to be generated
Currently, whenever I need to access the text value of a OptionSetValue, I use this code:
var textValue = OptionSetCache.GetText(service, entity, e => e.New_MyOptionSet);
The option set cache will use the entity.LogicalName, and the property expression to determine the name of the option set that I'm asking for. It will then query the SDK using the RetrieveAttriubteRequest, to get a list of the option set int and text values, which it then caches so it doesn't have to hit CRM again. It then looks up the int value of the New_MyOptionSet of the entity and cross references it with the cached list, to get the text value of the OptionSet.
Instead of doing all of that, I can just do this (assuming that the entity has been retrieved from the server, and not just populated client side):
var textValue = entity.FormattedValues["new_myoptionset"];
but the "new_myoptionset" is no longer early bound. I would like the early bound entity classes that gets generated to also generate an extra "Text" property for OptionSetValue properties that calls the above line, so my entity would have this added to it:
public string New_MyOptionSetText {
return this.GetFormattedAttributeValue("new_myoptionset"); // this is a protected method on the Entity class itself...
}
Could you utilize the CrmServiceUtil extension that will generate enums for your OptionSets and then add your new_myOptionSetText property to a partial class that compares the int value to the enums and returns the enum string
Again, I think specifically for this case, getting CrmSvcUtil.exe to generate the code you want is a great idea, but more generally, you can access the property name via reflection using an approach similar to the accepted answer # workarounds for nameof() operator in C#: typesafe databinding.
var textValue = entity.FormattedValues["new_myoptionset"];
// becomes
var textValue = entity.FormattedValues
[
// renamed the class from Nameof to NameOf
NameOf(Xrm.MyEntity).Property(x => x.new_MyOptionSet).ToLower()
];
The latest version of the CRM Early Bound Generator includes a Fields struct that that contains the field names. This allows accessing the FormattedValues to be as simple as this:
var textValue = entity.FormattedValues[MyEntity.Fields.new_MyOptionSet];
You could create a new property via an interface for the CrmSvcUtil, but that's a lot of work for a fairly simple call, and I don't think it justifies creating additional properties.
I have class name called "Address" in two namespaces. Its been two EDMX files, so it holds
different namespace in client side. I have another class "Vendor" and it holds object of "Address" class. In one situation i have to convert from one namespace to another namespace.
How i can achieve this.
You do not cast namespaces, you resolve types by qualifying them with a namespace.
Generally it is a bad idea to have multiple classes with the same name, especially if they are used together somewhere in the application.
It is not possible automatically. Namespace is really just a prefix of name of class. Essentially they are completely different classes with nothing in common.
Unless one Address class is derived from the other one, you cannot cast between the two at all. What you can do is give the classes some kind of "conversion constructor" that takes an object of the respective other class and maps the fields to its own ones:
namespace NS1
{
public class Address
{
// fields go here
public Address(NS2.Address add2)
{
this.Name = add2.Name;
this.Street = add2.Street;
// etc.
}
}
}
Casting namespace is conceptually incorrect. It’s more appropriate to say casting from one type to another. Unless the two classes are related in terms of inheritance, you cannot use casting at all.
I have a method on an object oriented database that creates tables based on their type.
I want to be able to send a list of types to get created, but i'm hoping to limit them to only classes derived from a specific base class (MyBase).
Is there a way i can require this in the method signature?
Instead of
CreateTables(IList<Type> tables)
Can i do something that would
CreateTables(IList<TypeWithBaseTypeMyBase> tables)
I know i could check the base class of each type sent over, but if possible i'd like this verified at compile time.
Any suggestions?
You could do the following:
CreateTables(IList<MyBase> tables)
{
// GetType will still return the original (child) type.
foreach(var item in tables)
{
var thisType = item.GetType();
// continue processing
}
}
Have you tried this?
CreateTables(IList<MyBase> tables)
I think that's all you have to do.
Why not just change the signature to:
CreateTables(IList<BaseType> tables)
I have an entity that, in addition to a few common properties, contains a list of extended properties stored as (Name, Value) pairs of strings within a collection. I should probably mention that these extended properties widely vary from instance to instance, and that they only need to be listed for each instance (there won't be any queries over the extended properties, for example finding all instances with a particular (Name, Value) pair). I'm exploring how I might persist this entity using Windows Azure Table Services. With the particular approach I'm testing now, I'm concerned that there may be a degradation of performance over time as more distinct extended property names are encountered by the application.
If I were storing this entity in a typical relational database, I'd probably have two tables to support this schema: the first would contain the entity identifier and its common properties, and the second would reference the entity identifier and use EAV style row-modeling to store the extended (Name, Value) pairs, one to each row.
Since tables in Windows Azure already use an EAV model, I'm considering custom serialization of my entity so that the extended properties are stored as though they were declared at compile time for the entity. I can use the Reading- and Writing-Entity events provided by DataServiceContext to accomplish this.
private void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e)
{
MyEntity Entry = e.Entity as MyEntity;
if (Entry != null)
{
XElement Properties = e.Data
.Element(Atom + "content")
.Element(Meta + "properties");
//select metadata from the extended properties
Entry.ExtendedProperties = (from p in Properties.Elements()
where p.Name.Namespace == Data && !IsReservedPropertyName(p.Name.LocalName) && !string.IsNullOrEmpty(p.Value)
select new Property(p.Name.LocalName, p.Value)).ToArray();
}
}
private void OnWritingEntity(object sender, ReadingWritingEntityEventArgs e)
{
MyEntity Entry = e.Entity as MyEntity;
if (Entry != null)
{
XElement Properties = e.Data
.Element(Atom + "content")
.Element(Meta + "properties");
//add extended properties from the metadata
foreach (Property p in (from p in Entry.ExtendedProperties
where !IsReservedPropertyName(p.Name) && !string.IsNullOrEmpty(p.Value)
select p))
{
Properties.Add(new XElement(Data + p.Name, p.Value));
}
}
}
This works, and since I can define requirements for extended property names and values, I can ensure that they conform to all the standard requirements for entity properties within a Windows Azure Table.
So what happens over time as the application encounters thousands of different extended property names?
Here's what I've observed within the development storage environment:
The table container schema grows with each new name. I'm not sure exactly how this schema is used (probably for the next point), but obviously this xml document could grow quite large over time.
Whenever an instance is read, the xml passed to OnReadingEntity contains elements for every property name ever stored for any other instance (not just the ones stored for the particular instance being read). This means that retrieval of an entity will become slower over time.
Should I expect these behaviors in the production storage environment? I can see how these behaviors would be acceptable for most tables, as the schema would be mostly static over time. Perhaps Windows Azure Tables were not designed to be used like this? If so, I will certainly need to change my approach. I'm also open to suggestions on alternate approaches.
Development storage uses SQL Express to simulate cloud table storage. Ignore what you see there... the production storage system doesn't store any schema, so there's no overhead to having lots of unique properties in a table.