I've been looking for an entity mapping library to save me from writing tons of property mapping code. So I found AutoMapper, AgileMapper and Mapster. As I see it, all help with similarly structured entities. But in my case, my two entities are not even remotely alike.
One property for example:
public class EntityA
{
public int PropertyA;
}
public class EntityB
{
public Inner1 inner1;
}
public class Inner1
{
public Inner2 inner2;
}
public class Inner2
{
public double nothingLikeTheOtherPropName
}
And EntityA.PropertyA maps to Inner2.nothingLikeTheOtherPropName.
So, the question is: Will any entity mapping library help if the two entities are structurally different?
AutoMapper can be configured to map the different properties, but there’s no way to automate completely different names.
The good thing is that you’d only do it once and everywhere else it’s used will be correct.
Here’s a previous answer
How to specify mapping rule when names of properties differ
Related
I have a model as follows.
public class Holder
{
...
public List<Thing> Future { get;set; }
public List<Thing> Past { get;set; }
}
public class Thing
{
...
public Holder Holder { get; set; }
}
Now I try to use Fluent API to tell the DB that each Holder can only have many things in its future and, also, many things in the past. A thing can only be future or past but never both, so a thing is only related to a single holder but a holder may have multiple things (distributed between the two arrays).
The best of my experience was to to the following.
private static void OnModelCreating(EntityTypeBuilder<Thing> entity)
{
...
entity.HasOne(_ => _.Holder).WithMany(_ => _.Future);
entity.HasOne(_ => _.Holder).WithMany(_ => _.Past);
}
However, when I try to create a migration, EF complains about it like so.
Cannot create a relationship between 'Holder.Future' and 'Thing.Holder', because there already is a relationship between 'Holder.Past' and 'Thing.Holder'. Navigation properties can only participate in a single relationship.
I'm not sure how to resolve it the right and proper way. The only work-around I got to fly was to declare a class FutureThing and PastThing, effectively duplicating the source code. That's ugly and bad.
It's a bit unusual scenario and all the googling leads to the howto's for setting up simpler relations. I'm using Core 2 and I expect that there's something that facilitates this scenario.
How should I figure here?
EF Core has a "code first mentality" by default, i.e. it is supposed to be used in a code-first manner, and even though database-first approach is supported, it is described as nothing more than reverse-engineering the existing database and creating code-first representation of it. What I mean is, the model (POCO classes) created in code "by hand" (code-first), and generated from the database (by Scaffold-DbContext command), should be identical.
Surprisingly, official EF Core docs demonstrate significant differences. Here is an example of creating the model in code: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html And here is the example of reverse-engineering it from existing database: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html
This is the entity class in first case:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
and this is the entity class in second case:
public partial class Blog
{
public Blog()
{
Post = new HashSet<Post>();
}
public int BlogId { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Post { get; set; }
}
The first example is a very simple, quite obvious POCO class. It is shown everywhere in the documentation (except for the examples generated from database). The second example though, has some additions:
Class is declared partial (even though there's nowhere to be seen another partial definition of it).
Navigation property is of type ICollection< T >, instead of just List< T >.
Navigation property is initialized to new HashSet< T >() in the constructor. There is no such initialization in code-first example.
Navigation property is declared virtual.
DbSet members in a generated context class are also virtual.
I've tried scaffolding the model from database (latest tooling as of this writing) and it generates entities exactly as shown, so this is not an outdated documentation issue. So the official tooling generates different code, and the official documentation suggests writing different (trivial) code - without partial class, virtual members, construction initialization, etc.
My question is, trying to build the model in code, how should I write my code? I like using ICollection instead of List because it is more generic, but other than that, I'm not sure whether I need to follow docs, or MS tools? Do I need to declare them as virtual? Do I need to initialize them in a constructor? etc...
I know from the old EF times that virtual navigation properties allow lazy loading, but it is not even supported (yet) in EF Core, and I don't know of any other uses. Maybe it affects performance? Maybe tools try to generate future-proof code, so that when lazy-loading will be implemented, the POCO classes and context will be able to support it? If so, can I ditch them as I don't need lazy loading (all data querying is encapsulated in a repo)?
Shortly, please help me understand why is the difference, and which style should I use when building the model in code?
I try to give a short answer to each point you mentioned
partial classes are specially useful for tool-generated code. Suppose you want to implement a model-only derived property. For code first, you would just do it, wherever you want. For database first, the class file will be re-written if you update your model. So if you want to keep your extension code, you want to place it in a different file outside the managed model - this is where partial helps you to extend the class without tweaking the auto-generated code by hand.
ICollection is definitely a suitable choice, even for code first. Your database probably won't support a defined order anyway without a sorting statement.
Constructor initialization is a convenience at least... suppose you have either an empty collection database-wise or you didn't load the property at all. Without the constructor you have to handle null cases explicitely at arbitrary points in code. Whether you should go with List or HashSet is something I can't answer right now.
virtual enables proxy creation for the database entities, which can help with two things: Lazy Loading as you already mentioned and change tracking. A proxy object can track changes to virtual properties immediately with the setter, while normal objects in the context need to be inspected on SaveChanges. In some cases, this might be more efficient (not generally).
virtual IDbSet context entries allow easier design of testing-mockup contexts for unit tests. Other use cases might also exist.
Imagine I have a hierarchy of objects I want to store in my Entity Framework 4.1 data store. I am creating them using Code First. They look like this:
BasicState
has many -> StatefulEntities
has a -> CreationDate
ReceivedState
has a -> EntityLocation
ApprovedState
has a -> EntityLocation
OrderedState
has a -> Order
DispatchedState
has a -> Order
has a -> DispatchNumber
The BasicState is the parent for all the other states, everything else shares those two fields/relationships.
My initial thought, and the way I have implemented this, was to use Table Per Hierarchy inheritance because it seemed that I could just inherit from BasicState and have my other states partake of those common properties.
However that caused a problem because when different states share a field, the underlying data model doesn't, so for example, my database would have EntityLocation_Id from one of ReceivedState and ApprovedState and EntityLocation_Id1 from the other. That makes it hard to create test data as you don't know what fields belong to what models. I asked about this previously.
The solution I went for was along these lines:
public abstract class BaseState
{
public DateTime CreatedDate { get; set; }
public ICollection<StatefulEntity> StatefulEntities{get;set;}
}
public abstract class LocationState : BaseState
{
public Location EntityLocation { get; set; }
}
public class ReceivedState : LocationState
{
}
public class ApprovedState : LocationState
{
}
This worked partially, however although it created a single EntityLocation_Id it still created two Order_Ids for OrderedState and DispatchedState, even though they behave in the same way and the implementations are indistinguishable.
With that barely half solved, I have now hit another problem which is leading me to ask this question:
Given that I the relationship between BasicState and StatefulEntities is many to many in both directions, I need to be able to find the Order details from the OrderedStates belonging to a StatefulEntity.
The problem is that although this is quite easy to represent in SQL, the inheritance involved means that Entity Framework doesn't know whether any given BasicState is an OrderedState so there appears to be no way to do a single trip to the database to include the OrderedState.Order.
So what I can't do is something like this:
statefulEntityRepository.Get().Where( x => x.Id == 1 ).Include( x => x.BasicStates ).Include( x.BasicStates.Order );
Obviously, that isn't code that would run but it shows what the problem is- the Order only belongs to certain subtypes of BasicState and so EF won't preload it, even if I am using some kind of cast.
If I try projection I could get something like this:
statefulEntityRepository.Get().Select( x=> new {
StatefulEntity = x,
EntityLocation = ( from state in x.BaseStates where state is ReceivedState select state.EntityLocation )
}
But having got that I need to find my way back from the anonymous type returned by the projection to my StatefulEntity for the rest of my code to be able to handle it, which feels like a significant longcut.
I have got as far as trying to define my base class and inheritors thus:
public abstract class BaseState
{
public DateTime CreatedDate { get; set; }
public ICollection<StatefulEntity> StatefulEntities{get;set;}
public long EntitytLocationId { get; set; }
}
public abstract class LocationState : BaseState
{
[Column(name="EntityLocationId")]
public Location EntityLocation { get; set; }
}
And so on, but then I seem to be breaking the basic point of having TPH in the first place and I feel as though I might as well be rolling my own object model over a generic data class.
Edit: I think I have a little more understanding of this now- from trying to set the ForeignKey on the far end of that relationship ( i.e. the relationship between Location and LocationState ) it looks as though the inverse collection on the Order or the Location can't talk to a property that isn't on the base object, so I would have to use the version above. This creates a new problem in how I manage cases which have no EntityLocationId or OrderId- if I make those fields nullable it raises an error that reference fields cannot be null during database creation and by default there is no way to set an initial value on a field in Code First.
Can anyone recommend a better way of representing this type of model that will work with Entity Framework?
I'm studying Fluent NHibernate now, and have a question about mapping. It's not an issue, but a best practice question.
I know that with Fluent NHibernate there is a new fluent mapping, and it requires a new Class for mapping fields that will be used by the Entity Class. I was wondering, if the Mapping Class is directly linked to the Entity Class (It will map exacly for the entity class), do best practices dictate that they can't be joined within the same .cs file?
Please note that there will be no nesting here.
I.e.: There are Product and a ProductMap classes, both for a Product table on my database, so I'd place both classes within the same Product.cs, like the following:
namespace Business.Entity
{
public class Product
{
...
}
public class ProductMap : ClassMap<Product>
{
...
}
}
If the classes shouldn't be inside the same file, would you care to explain why, and maybe with real examples?
Thanks in advance!
When creating the SessionFactory instance, you will pass a class that tells which assembly has the mapping definitions. Then, using reflection, it'll iterate through all the classes on this assembly that inherit from ClassMap<T>.
That said, for a faster initialisation, it's better to have this assembly as light as possible, and it means that it would be better to have an assembly that would hold only the mappings and not the classes definitions.
AFAIK this is the only difference. Any feedback will be appreciated.
You should design your entities persistant ignorant as much as possible.
That means you shouldn't make Product derive from ClassMap<Product>. But it also means that the ProductMap shouldn't even be in the same project as your entity.
Typically, you would have a DAL project that contains the mapping and a Domain / Business project that contains the entity
You can keep both classes in different files, even in different namespace. but if you are beginner then you can keep entity class in different file and map class in different file within same namespace.
/* Product.cs */
namespace Business.Entity
{
public class Product
{
...
}
}
/* ProductMap.cs */
namespace Business.Entity
{
public class ProductMap : ClassMap<Product>
{
...
}
}
Just another question about custom extended properties in Entity Framework entities.
Entity model is quite simple in general. Of course in reality it is more complicated, but just for simplyfing I am not pasting all the generated code, just classes and needed properties.
So, I have the entity classes:
partial class Calibration
{
public string Identifier {get;set;}
public Device CalibratedDevice {get;set;}
}
partial class Device
{
public string Name {get;set;}
public ModelGroup ModelGroup {get;set;}
}
partial class ModelGroup
{
public Model[] Models {get;set;}
}
partial class Model
{
public Name {get;set;}
}
And I need to extend Calibration class with additional calculated property in another file.
partial class Calibration
{
public string ModelGroupName {get;set;}
}
This property is calculated like this:
string.Join(" / ", CalibratedDevice.ModelGroup.Models.Select(m => m.Name));
And finally I need to sort ObjectSet of Calibration entities by this calculated property.
Of course, code like
Calibrations.OrderBy(c => c.ModelGroupName)
will not work with throwing an exception, because EF cannot translate ModelGroupName property to database.
Of course, I know the easiest way to do it:
Calibrations.AsEnumerable().OrderBy(c => c.ModelGroupName)
And of course, it doesn't works for me, I don't want to load all the objects from data storage and sort them in linq because I need only a small piece of the whole ordered object set.
I know the approach with storing calculation lambdas instead of properties and passing it to OrderBy method, but it doesn't works either because I have more complex calculation logic than simple a + b.
For example
partial class Calibration
{
public static Expression<Func<Calibration, string>> ModelGroupName
{
get
{
return c => string.Join(" / ", c.CalibratedDevice.ModelGroup.Models.Select(m => m.Name));
}
}
}
Calibrations.OrderBy(Calibration.ModelGroupName)
will throw an Exception because EF cannot thanslate string.Join method to database.
I worked with the first version of EF and this annoying method-translation mechanism was a disaster. And now after few years of EF evolution this problem exists and I can found any suitable solution.
So, please, suggest the ways to organize IQueryable EF sorting by custom properties with calculation logic witch is not directly translated to SQL.
Thanks for replies.
You can map SQL functions to CLR functions in Entity Framework.
Here's a tutorial on how it is done:
http://blogs.microsoft.co.il/blogs/gilf/archive/2009/05/28/entity-sql-user-defined-functions-in-entity-framework-4.aspx
Please let me know if you need further help.
EF converts IQueryable objects into SQL statements that run on a db. You're asking if EF can translate arbitrary C# code into SQL - no, it can't.
It might be possible to construct a query that returns the right result set, which your custom properties can use - it depends on the logic.