I'm trying to figure out, how to implement navigation properties to my entities... But my navigation properties is always null:
I've set up two entities:
Entity 1 contains this lines:
public int Id { get; set; }
public ICollection<BestellterArtikel> BestellteArtikel { get; set; }
My second entity looks like this:
public int Id { get; set; }
public int BestellungId { get; set; }
public Bestellung BestellteArtikel { get; set; }
Further more I included this line to my overwritten OnModelCreating-Method:
modelBuilder.Entity<Bestellung>().HasMany(e => e.BestellteArtikel).WithRequired(e => e.Bestellung);
What have I done wrong? Have I forgotten something important? And does it has to be so complex? Do I have to add a line in my overwritten method for each property?
Here is my solution :
Entity 1:
public virtual ICollection<BestellterArtikel> BestellteArtikel { get; set; }
Entity 2:
public virtual Bestellung BestellteArtikel { get; set; }
Edited:
also you have to revise your mapping:
modelBuilder.Entity<Bestellung>().HasMany(e => e.BestellteArtikel).WithRequired(e => e.BestellteArtikel );
Instead of referring to BestellteArtikel property, you referred to type!
What do you mean by "always null"?
If you are talking about null values when you try to read them from DB,
then remember that you need to eagerly load the navigation properties when you query the context,
or use EF lazy-loading.
Read this for more information.
Related
I have the following two classes
public class Tip
{
public string Home { get; set; }
public string Away { get; set; }
public string Prediction { get; set; }
public Tipster Tipster { get; set; }
... other properties
}
public class Tipster
{
public int Id { get; set; }
public string Username { get; set; }
public string Platform { get; set; }
}
Now, I want to make unique index in theTip table. According to the EF Core documentation, there is no Data Annotations syntax, so I am using the fluent one:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Tip>()
.HasIndex(entity => new { entity.Tipster, entity.Home, entity.Away, entity.Prediction })
.HasName("IX_UniqueTip")
.IsUnique();
}
Now, when I update the database I get the following error
C:..>dotnet ef database update System.InvalidOperationException:
Cannot call Property for the property 'Tipster' on entity type 'Tip'
because it is configured as a navigation property. Property can only
be used to configure scalar properties.
It seems that EF didn't liked the fact that I am using referential property in the index. How can I fix that ?
You can't use navigation property in index defining expression. Instead, you should use the corresponding FK property.
The problem in your case is that you don't have explicit FK property in your model Tip. By convention EF Core will create int? TipsterId shadow property. So theoretically you should be able to use EF.Property method to access it:
.HasIndex(e => new { TipsterId = EF.Property<int>(e, "TipsterId"), e.Home, e.Away, e.Prediction })
Unfortunately this doesn't work currently (EF Core 2.0.1). So you have to resort to HasIndex overload with params string[] propertyNames:
.HasIndex("TipsterId", nameof(Tip.Home), nameof(Tip.Away), nameof(Tip.Prediction))
You must define the property TipsterId explicitly cause the Navigation property define it as shadow, so you cannot use it on custom index or alternate key
public class Tip
{
public string Home { get; set; }
public string Away { get; set; }
public string Prediction { get; set; }
public int TipsterId { get; set; }
public Tipster Tipster { get; set; }
... other properties
}
Now you can
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Tip>()
.HasIndex(entity => new { entity.TipsterId, entity.Home, entity.Away, entity.Prediction })
.HasName("IX_UniqueTip")
.IsUnique();
}
They way you defined your entities EF will put the referential column into the tipster table, since it looks like a 1-n relationship. Meaning a tipster can place several tips, but each tip is only placed by a single tipster.
That means on the database level there is nothing to index. No column, no key - nothing.
To fix this you might ask yourself what you really want to achieve with an index in the first place. An index is supposed to make queries using the columns of the index faster and avoid a full table scan.
I recently delete a column ConversationId from my tables. When I start to debug my service and try to save I am getting an error:
Invalid column name 'ConversationId'.
Code:
public class AstootContext : DbContext
{
public AstootContext(DbContextOptions<AstootContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
public DbSet<ServiceRequest> ServiceRequests { get; set; }
}
And my entity looks like this:
public class ServiceRequest
{
public int Id { get; set; }
public int SenderUserId { get; set; }
public int PriceTypeId { get; set; }
public decimal Price { get; set; }
public bool IsAccepted { get; set; }
public DateTime Created { get; set; }
public int MessageId { get; set; }
}
All references to ConversationId were removed from the code, I've rebuilt, yet I'm still getting this error and I don't understand why.
This is my SQL Server table as you can see there is no ConversationId:
Is there a secret cache that I need to delete or something I have to run to update this?
EF Core is code based ORM, with the most important here being the M - Mapper. It doesn't matter what the actual database structure is, the important is what EF *thinks** it is based on your code model (entity classes and their properties, combined with data annotations, fluent configuration and set of conventions).
So the problem should originate from code. Since you've removed the explicit property, it should be caused by shadow property. And as explained in the documentation link, shadow properties are usually introduced by convention from relationships:
Shadow properties can be created by convention when a relationship is discovered but no foreign key property is found in the dependent entity class. In this case, a shadow foreign key property will be introduced.
The documentation also explains the naming rules applied in different scenarios.
A shadow property called ConversationId can be introduced in a several ways, but according to the provided information, the most likely cause is to have an entity class called Conversation defining one-to-many relationship with ServiceRequest by having a collection type navigation property:
public class Conversation
{
public int Id { get; set; }
// ...
public ICollection<ServiceRequest> ServiceRequests { get; set; }
}
Which according to your comment was indeed the case.
For completeness, here are some other possible scenarios generating such property:
(1) No collection navigation property in Conversation, reference navigation property in ServiceRequest:
public class Conversation
{
public int Id { get; set; }
// ...
}
public class ServiceRequest
{
// ...
public Conversation Conversation { get; set; }
}
(2) No navigation properties in Conversation and ServiceRequest, fluent configuration:
modelBuilder.Entity<Conversation>()
.HasMany<ServiceRequest>();
or
modelBuilder.Entity<ServiceRequest>()
.HasOne<Conversation>();
or variations of the above.
(3) No relationship involved, shadow property created through fluent configuration:
modelBuilder.Entity<ServiceRequest>()
.Property<int>("ConversationId");
I am trying to use ExpressMapper to map data entities to models.
If I map entity to a model directly (both of them having same properties) then it is working fine.
But if I map linked entities to model then I am getting an error
There was an error: System.MissingMethodException: No
parameterless constructor defined for this object.
Database structure:
ExpressMapper Registration:
Mapper.Register<DiscountDaysOfWeek, DiscountDaysOfWeekModel>()
.Member(dest => dest.DiscountDayId, src => src.DiscountDayId)
.Member(dest => dest.DiscountDaysOfWeekId, src => src.DiscountDaysOfWeekId)
.Member(dest => dest.DiscountId, src => src.DiscountId)
.Member(dest => dest.Discountday, src => src.DiscountDay.Day);
Invoked like this:
var disDays = discs.SelectMany(x => x.DiscountDaysOfWeeks)
.Map<IQueryable<DiscountDaysOfWeek>, IQueryable<DiscountDaysOfWeekModel>>();
Getting the error message at the invoke.
DiscountDaysOfWeekModel:
public class DiscountDaysOfWeekModel
{
public int DiscountDaysOfWeekId { get; set; }
public int DiscountId { get; set; }
public int DiscountDayId { get; set; }
public string Discountday { get; set; }
}
DiscountDayOfWeek (Generated by EF)
public partial class DiscountDaysOfWeek
{
public int DiscountDaysOfWeekId { get; set; }
public int DiscountId { get; set; }
public int DiscountDayId { get; set; }
public virtual DiscountDay DiscountDay { get; set; }
public virtual Discount Discount { get; set; }
}
DiscountDay(Generated by EF):
public partial class DiscountDay
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public DiscountDay()
{
this.DiscountDaysOfWeeks = new HashSet<DiscountDaysOfWeek>();
}
public int DiscountDayId { get; set; }
public string Day { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<DiscountDaysOfWeek> DiscountDaysOfWeeks { get; set; }
}
Sample working one: In the below working sample the model and entities are having same properties
Mapper.Register<DiscountPreventedPriceEnding, DiscountPreventedPriceEndingModel>();
var execPriceEndings = discs.SelectMany(x => x.DiscountPreventedPriceEndings)
.Map<IQueryable<DiscountPreventedPriceEnding>, IQueryable<DiscountPreventedPriceEndingModel>>();
Any help would be greatly appreciated.
I appreciate this is an extremely old question, but given that I just spent 4 hours debugging a similar There was an error: System.MissingMethodException: No parameterless constructor defined for this object error on ExpressMapper, I thought I'd chime in with my findings.
So we had a situation similar to yours, in that we had domain models like so (all the following is simplified examples):
public class Owner
{
public int? ID { get; set; }
public string Name { get; set; }
}
public class Animal
{
public int? ID { get; set; }
public string Name { get; set; }
public int? OwnerID { get; set; }
[ForeignKey("OwnerID")]
public Owner Owner { get; set; }
}
With the following view model (i.e. what our APIs send out and receive):
public class AnimalViewModel
{
public int? ID { get; set; }
public string Name { get; set; }
public string Owner { get; set; }
}
With mappings like so:
Mapper.Register<Animal, AnimalViewModel>();
Mapper.Register<AnimalViewModel, Animal>();
On mapping to or from the domain model and the view model we'd get the MissingMethodException, despite the fact that both the view model and the domain model had public, default constructors. The solution was to manually map the related entities in the domain model and exclude them from ExpressMapper's mappings like so:
Mapper.Register<Animal, AnimalViewModel>()
.Ignore(a => a.Owner);
Mapper.Register<AnimalViewModel, Animal>()
.Ignore(a => a.Owner);
From reading EntityMapper's source code, it seems the MissingMethodException is a total red herring which has nothing to do with the actual issue. The actual issue seems to be that it can't figure out how to convert one type to another. In our case -- where complex objects were mapped to/from primitives as above -- it was sufficient to exclude the related objects from the mapper and do it manually.
EDIT:
Upon further investigation, we traced the root problem in our case back to the fact that EF proxy creation creates generated types (e.g. 'MyModel_14289012') which don't match the types registered in the mapper. To prevent this, apply the following to your context:
Context.Configuration.LazyLoadingEnabled = false;
Context.Configuration.ProxyCreationEnabled = false;
and manually include any nested/related objects required in your model like so:
Context.Animals
.Include(a => a.Owner);
This fetches the related entities, but as their actual type rather than the EF-generated type.
Entity Framework uses a parameterless constructor to instantiate classes and reflection to populate class properties. If you have constructors with parameters, then the default parameterless constructor is hidden and you have to add it to your Entity classes for Entity Framework to use.
But if I map linked entities to model then I am getting an error
If your child entities are missing the parameterless constructor and lazy loaded, then EF is failing when it attempts to instantiate the child entity which doesn't have a parameterless constructor.
Note: the parameterless constructor doesn't have to be public.
I am using EntityFramework for the first time and maybe this question is so simple...I've used code first method..I have a Class Personnel which looks like this:
public class Personnel
{
public string Id { set; get; }
public int Code { set; get; }
public string Name { set; get; }
public int Type { set; get; }
public JobTitle Title { set; get; }
}
and the JobTitle class:
public class JobTitle
{
public string Id { set; get; }
public int Number { set; get; }
public string Title { set; get; }
public List<Personnel> Personnels { set; get; }
}
which the last property in Personnel Class is a foreign key in personnel table of course..my problem is when I want to retrieve all personnels ( or a personnel ) from DB using lambda expression..the foreign key object is null..the lambda expression is like below:
Context.ContextInstance.Personnels.ToList();
and if I change the expression to this the foreign key object is not null any more.
Context.ContextInstance.Personnels.Include("Title").ToList();
is it the right way??..is there any better way??..I supposed that EF will automatically understand that!!!!..if there are more than 1 FK then I have to use Include for all of them?? please help me to understand.
Thanks
This is due to lazy loading. When you call Context.ContextInstance.Personnels.ToList(); this will fetch all personnel's but Title will not fetch until it get instanced, so make it virtual to get it.
or, you can disable lazy loading by
public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext") {
this.Configuration.LazyLoadingEnabled = false;
}
Doing this will get all related data from context. Using "include" is loading on demand, when you specify properties you want to query.
Virtual keyword allows entity framework runtime create dynamic proxies for your entity classes and their properties, and by that support lazy loading. Without virtual, lazy loading will not be supported, and you get null on collection properties.
If your JobTitle property would be defined as virtual, you wouldn't need to use include.
It's really good explained here: Entity Framework 4.1 Virtual Properties
I am testing lazy loading in a C# Console Application. For some reason Lazy loading is not working.
I have checked the LazyLoadingEnabled and ProxyCreationEnabled properties of the context.Configuration. They are true.
My property is virtual.
I have checked the other similar SO questions without success. I am not sure what might be happening.
This is my code (simplified to not show namespaces):
static void Main(string[] args) {
Models.DataContext dc = new Models.DataContext();
Console.WriteLine("Context Lazy {0}. Proxy Creation {1} ",
dc.Configuration.LazyLoadingEnabled,
dc.Configuration.ProxyCreationEnabled);
var grp = dc.Groups.FirstOrDefault();
Console.WriteLine("GroupId {1}, AttrSet is null = {0}",
grp.AttrSet == null , grp.Id);
var grp2 = dc.Groups.Include("AttrSet").FirstOrDefault();
Console.WriteLine("GroupId {1}, AttrSet is null = {0}",
grp2.AttrSet == null, grp2.Id);
}
class Group {
public System.Guid Id { get; set; }
public string Name { get; set; }
public virtual AttrSet AttrSet { get; set; }
}
class AttrSet {
public System.Guid Id { get; set; }
public string Name { get; set; }
}
The output of running this is:
Context Lazy True. Proxy Creation True
GroupId 186ebc8a-dec7-4302-9f84-5a575577baac, AttrSet is null = True
GroupId 186ebc8a-dec7-4302-9f84-5a575577baac, AttrSet is null = False
I am sure that the loaded record is correct and it has a proper AttrSet in the database.
Any ideas?
Update
I created a very simple testing project in case any one actually wants to look at the code.
See: https://bitbucket.org/josea/eflazy (GIT: https://josea#bitbucket.org/josea/eflazy.git).
Proxy generation is not occurring. Why?? Because your POCOs are PRIVATE!! EF can't see them to derive proxies from them. Make your POCOs public and it'll work the way you expect.
public class Group
Are you using anything to configure the 1:1 relationship between the 2 classes? Because it doesn't look like you are here, which would cause Entity Framework to not be able to load the relationship.
You can use Data Annotations to define the FK relationship as so:
public class AttrSet {
public System.Guid Id { get; set; }
public string Name { get; set; }
[Required, ForeignKey("MyGroup")]
public int GroupID { get; set; }
public virtual Group MyGroup { get; set; }
}
This should give you the relationship you wanted. AttrSetId is whatever you've named the FK column in your table, so change that if it is different.
public class Group {
public System.Guid Id { get; set; }
public string Name { get; set; }
public System.Guid AttrSetId {get;set;}
[ForeignKey("AttrSetId")]
public virtual AttrSet AttrSet { get; set; }
}
Edit:
Add this line to your AttrSet class:
public virtual ICollection<Group> Groups {get;set;}
Add this next line to your OnModelCreating in your Models.DataContext. If for some reason you don't already have that function overridden, it'll look like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Group>().HasOptional(x => x.AttrSet).WithMany(x => x.Groups);
}
I put HasOptional instead of HasRequired as I assumed you could save a Group without an AttrSet. If that is not true, and the FK is not nullable, then you should use HasRequired.