WithOptional with Entity Framework Core - entity-framework

I'm trying to migrate my old app to the new EF Core but I cannot find some relationships like:
HasRequired(o => o.Document).WithOptional(o => o.CancelNote);
Is there some extension methods? I cannot find on the docs.
The HasRequired I think that is possible to substitute with HasOne() method, but how about the WithOptional()?
Other thing, according to the docs the entity not uses the virtual keyword to create the navigation properties, how lazy load will work?

You will not find an HasOptional equivalent method in EF7. By convention if your FK property is nullable, you navigation property will be treated as optional
modelBuilder.Entity<Blog>()
.HasOne(p => p.Document)
.WithOne(i => i.CancelNote)
.HasForeignKey<Document>(b => b.CancelNoteForeignKey);
About your second question,EF Core (EF7) doesn't support Lazy Loading. In this link you will find the options you have now to load related entities

Related

EF Core: Automaticall Save Enums as Strings Without Calling HasConversion For Every Single Property

Using EF Core I can tell the modelBuilder to save properties having of enum type as string:
modelBuilder
.Entity<MyEntity>()
.Property(e => e.SomeEnumProperty)
.HasConversion<string>();
This has been asked and answered several times and is also described in the official docs.
However, the list of entitiy types (modelBuilder.Model.GetEntityTypes()) and their subtypes used in my project is rather lengthy and I image it to be error prone to loop over all managed entities, get their properties and their children properties recursivly via reflection and kind of semi-manually add the string conversion.
Is there a builtin way to automatically save all enum property values as strings using the StringEnumConverter?
Currently (EF Core 3.1.7) there is no other way than the one described in EF CORE 2.1 HasConversion on all properties of type datetime.
The difference here is the way of identifying Enum type properties, and due to the lack of easy public way of getting entity type builder (this property builder), the direct usage of SetProviderClrType metadata API instead of more intuitive HasConversion:
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
var propertyType = Nullable.GetUnderlyingType(property.ClrType) ?? property.ClrType;
if (propertyType.IsEnum)
property.SetProviderClrType(typeof(string));
}
}
This must be at the end of your OnModelCreating override, or more specifically, after all entity types have been discovered.

How incapsulate dbquery into automapping profile

I try to pass from EF entity to dto in business layer.
So I setup Automapper and everything goes well.
Here is my profile class:
public DocumentProfile()
{
CreateMap<Data.Models.Docflow.Package, PackageDto>()
.ForMember(dest => dest.ReceiverName, opt => opt.MapFrom(src => src.Receiver.FullName))
.ForMember(dest => dest.SenderName, opt => opt.MapFrom(src => src.Sender.FullName))
;
}
But I make mapping from Package to PackageDto in different places of my code. And I have different specific queries in different cases. So I need to remember to include navigation properties Receiver and Sender in all queries.
So how can I incapsulate single query for Package entity with all necessary properties for certain projection?
I saw examples with value resolvers and type converters but it seems not suitable.
#lucian-bargaoanu, thanks for your comments!
Finally I came in to 2 suitable solutions.
Shared part is:
I prepare function like PackageDto Get(Guid packageId) in Repository and I incapulate dbquery with mapping to dto in repository and in BL I work only with dto.
But the difference is:
dbquery returns needed entity type in memory that is mapped then by Mapper.Map<>
dbquery returns IQueryable, that then extended by ProjectTo
Anyway It's necessary set profile with mapping rules, but second way is clearly as it performs includes that you need automatically.

Entity Framework Ignore property by conventions

I have a code-first model where all entities are derived from a Entity base class. I have a property IsDeleted in base class which I want to ignore in all entities (I cannot remove/comment IsDeleted property since base class is used in many projects). Is there a way to configure modelBuilder to ignore this property form all entities (by conventions, I think), without to specify modelBuilder.Entity<...>().Ignore(l => l.IsDeleted) for all entities from my model?
Thanks,
Ion
You can do this using the new EF 6.1 Custom Code First Conventions:
modelBuilder.Types().Configure(c => c.Ignore("IsDeleted"));
This will ignore any property of the name IsDeleted in any of your types.
If you only want to do this for classes inheriting a certain base class, you can do:
modelBuilder.Types()
.Where(t => t.IsSubclassOf(typeof(MyBaseClass)))
.Configure(c => c.Ignore("IsDeleted"));
You can use the [NotMapped] annotation on the properties, but that will still need to be added for each entity which isn't the same as only specifying it once and having a convention for ignoring it.

More automatic way to use automapper to map to Entity Framework objects

I am mapping quite a few WCF Data Contracts to Entity Framework Classes.
For every class I have to do this kind of thing:
Mapper.CreateMap<MyContractClass, MyDalClass>()
.ForMember(x => x.EntityKey, opt => opt.Ignore())
.ForMember(x => x.SomeAssociation, opt => opt.Ignore())
.ForMember(x => x.SomeAssociationReference, opt=> opt.Ignore())
// Repeat
// the
// last
// /two
// lines
// for
// every
// single
// association
// (Some classes have a lot of associations)
;
Is there an easier way? Some way to rule out all the extra stuff put in by EntityFramework?
Or does this just have to be done by hand?
NOTE: I have extensively evaluated the POCO template and it does not work for my scenario. Please do not just recommend that instead of Automapper.
Assuming that your contract class doesn't have the association properties, you could use this extension method to ignore them all in one statement:
Mapper.CreateMap<MyContractClass, MyDalClass>().IgnoreAllNonExisting();
I'm using T4 templates to generate the mappings from the EDMX model. This works very well and has saved me a lot of time so far. The idea is from this guy. You can download his templates and customize them to work for your scenario.
You can use EntitiesToDTOs which is simpler than AutoMapper. You don't have to write the map, neither configurate it. It is all automatically generated by the tool.

Autofac registration with multiple assembies and differing EntityConnections

We have two Assemblies that contain their own Entity-Framework EDMX & repositoriy objects. These are registered using Autofac in an ASP.NET webapplication.
These Assemblies are very similar of architecture (but differing EDMX) we have found that the last EntityConnection being registered is the EntityConnection that is being used in both Assemblies. We need to limit the usage of an EntityConnection to only be used by Types of an assembly or namespace.
var assembly = typeof(Activity).Assembly;
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
builder.Register(reg => new EntityConnection(ConnectionString));
var assembly = typeof(User).Assembly;
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
builder.Register(reg => new EntityConnection(ConnectionString));
Is there a way to register the EntityConnection and limit the depth of EntityConnection? Limit each EntityConnection to the assembly it belong to?
Here's a pseudocode example of how we want to register EntityConnection for use in only an assembly or namespace.
builder.Register(reg => new EntityConnection(ConnectionString)).ForNamespace("x");
try to solve the problem at an higher level of abstraction. Since you have two separate domains (one containing the Activity entity, and one containing the User entity), it would be convenient to have this explicitly in your application design. For instance, define a factory of some kind per domain:
public interface IActivityDomainContextFactory
{
ObjectContext CreateNew();
}
public interface IPeopleDomainContextFactory
{
ObjectContext CreateNew();
}
You can now easily create an implementation for each interface, register them in the Autofac ContainerBuilder and let your services depend on one of those interfaces, instead of depending them on a EntityConnection.
In this case you of course still have a dependency on the Entity Framework itself (see here for how to abstract that away), but this makes your configuration much easier, less fragile, better performing, and your application code more maintainable.
I hope this helps.
You probably want to name/key your registrations. See TypedNamedAndKeyedServices - Autofac
I think this solves half your problem, how to register the types. The other half is in the resolution. Since your doing autoregistration via assembly scanning, this might take a little more trickery.
There are plenty of good suggestions out there on improving this, so just recording my solution as a general sketch of how you'd do this in Autofac.
The trick is to use named services for the connections, then customise parameter resolution for types in each assembly so that the EntityConnection parameters get a named instance:
builder.Register(reg => new EntityConnection(ConnectionString))
.Named<EntityConnection>("activities");
builder.RegisterAssemblyTypes(typeof(Activity).Assembly)
.AsImplementedInterfaces()
.WithParameter(
(pi, c) => pi.ParameterType == typeof(EntityConnection),
(pi, c) => c.ResolveNamed<EntityConnection>("activities"));
builder.Register(reg => new EntityConnection(ConnectionString))
.Named<EntityConnection>("users");
builder.RegisterAssemblyTypes(typeof(User).Assembly)
.AsImplementedInterfaces()
.WithParameter(
(pi, c) => pi.ParameterType == typeof(EntityConnection),
(pi, c) => c.ResolveNamed<EntityConnection>("users"));