EF Code first and optional:optional relationship - entity-framework

According to msdn article, the following should create an optional:optional relationship, but instead it creates optional:many relationship. Is the article wrong?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Optional_1>()
.HasKey(o1 => o1.id1);
modelBuilder.Entity<Optional_2>()
.HasKey(o2 => o2.id2);
modelBuilder.Entity<Optional_1>()
.HasOptional(o1 => o1.Dependent)
.WithOptionalPrincipal(o2 => o2.Principal);
}
public class Optional_1
{
public int id1 { get; set; }
public Optional_2 Dependent { get; set; }
}
public class Optional_2
{
public int id2 { get; set; }
public Optional_1 Principal { get; set; }
}
thank you

The table might look like one to many, but Entity Framework will enforce it as optional:optional because of the navigation properties. Since the navigation property is only a single object and not a collection, there is no way to add multiple.
If you look at the generated tables, it creates a nullable foreign key to your principal table (Optional_1). This allows you to create an Optional_2 that is not associated with an Optional_1.
If you were to insert multiple rows into Optional_2 that have the same foreign key to Optional_1 outside of EF, there wouldn't be anything preventing it from going through. If you were to try and load these entities you would get an error. You can't add a unique index to the column because it needs to allow NULL since it is optional.

Related

Entity Framework Code First Foreign Key Problems

I am trying to use EF Code First on an existing database. I first tried some of the reverse-engineering tools, but I ran into problems with that, so at the moment I am trying to hand-code some of the classes. I am having some trouble getting some of the foreign key relationships set up. Consider two tables. The first is called LocaleValueLookup:
public class LocaleValueLookup
{
public int Id { get; set; }
public Guid Guid { get; set; }
}
This table provides an Id for multi-language text held in a different table (that other table is not important for the purposes of this question). The second table is called SectionType, and it has an optional FK to LocaleValueLookup:
public class SectionType
{
public int EnumId { get; set; }
public string Name { get; set; }
public int? DefaultSectionTextLocaleValueLookupId { get; set; }
// Navigation property
public LocaleValueLookup DefaultSectionTextLocaleValueLookup { get; set; }
}
I have tried various things, including adding a [ForeignKey] attribute to the SectionType.LocaleValueLookup property, and various incantations in the DbContext.OnModelCreating() override, but when I query the DbContext, I can't get the DefaultSectionTextLocaleValueLookup to be anything but null. I can retrieve other objects from the context just fine, and I have verified that DefaultSectionTextLocaleValueLookupId is not null at least some of the time.
My OnModelBuilding() contains the following:
modelBuilder.Entity<LocaleValueLookup>()
.ToTable("LocaleValueLookup")
.HasKey(lvl => lvl.Id);
modelBuilder.Entity<LocaleValueLookup>().Property(lvl => lvl.Id).IsRequired();
modelBuilder.Entity<SectionType>()
.ToTable("SectionType")
.HasKey(st => st.EnumId);
modelBuilder.Entity<SectionType>().Property(st => st.EnumId).IsRequired();
A couple of other points:
I would prefer not to have a SectionType collection on the LocaleValueLookup object. LocaleValueLookup is a low-level class that a lot of other classes depend on, so to include a collection property on LocaleValueLookup for every other class that references it will make for an unwieldy class with a lot of collections on it that I don't need from a domain perspective.
I would prefer to do the mapping setup in DbContext.OnModelCreating() rather than using attributes on my model objects
Any help would be greatly appreciated!
It looks like your foreign key is nullable so that means an optional -> many relationship.
Could you try something like this:
modelBuilder.Entity<SectionType>()
.HasOptional(opt => opt.DefaultSectionTextLocaleValueLookup)
.WithMany() // no navigation on the other side
.HasForeignKey(fk => fk.DefaultSectionTextLocaleValueLookupId);
If you were to write a query like this you should get a value back:
var query =
from st in db.SectionTypes
where st.EnumId == 12345
select new
{
SectionType = st,
LocaleValue = st.DefaultSectionTextLocaleValueLookup
};
It will only be non-null if the foreign key has a value, obviously.

In Entity Framework, is it possible to auto-map a column to an entity property? ID => [tablename]ID

I want to use .Id in my entity classes for the unique id, but our dba wants [tablename]Id in the database tables. Is there a way that Entity Framework can make this mapping automatically without having to create a new map file for every entity?
As long as I understand you correctly, you have something like:
public class Foo
{
public Int32 ID { get; set; }
// ...
}
public class Bar
{
public Int32 ID { get; set; }
// ...
}
And, without too much effort (or creating multiple entityTypeConfiguration<T> models) you'd like something along the lines of the following outcome:
Current Mapping Desired Mapping
[Foo] [Foo]
ID FooID
... ...
[Bar] [Bar]
ID BarID
... ...
For this, a few methods exist (and depend on which version of EF you're using). With that said, some approachable tactics:
ColumnAttribute
You can visit each entity model and decorate the ID property with the ColumnAttribute. This tells EF that, despite what we named the column, we want something else to be the name within the database. e.g.
public class Foo
{
[Column("FooID")]
public Int32 ID { get; set; }
// ...
}
public class Foo
{
[Column("BarID")]
public Int32 ID { get; set; }
// ...
}
The only problem here is that you're now going to every model and adding the attribute.
OnModelCreating & Fluent Mapping
Another method is to do the mapping but keep it all in one place. The OnModelCreating event is great for this kind of thing.
public class MyDbContext : DbContext
{
public Dbset<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
protected override void OnmodelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>()
.Property(x => x.ID).HasColumnName("FooID");
modelBuilder.Entity<Bar>()
.Property(x => x.ID).HasColumnName("BarID");
}
}
Again, the problem here is that you're creating a configuration for each entity.
Custom Conventions
As of EF6, you can use Custom Conventions which make things easier (Including developing your own convention that would make ID=TableNameID). Unfortunately I don't have the time to write an example, but the docs are pretty enlightening.
According to MSDN , both way should work.
Primary key detection is case insensitive. Recognized naming patterns
are, in order of precedence: 'Id' [type name]Id

Foreign Key Not Mapped Correctly from Inheritance

If I have the following code generating my database it assigns a foreign key from the TankComponent table to the Asset table instead of the Tank table. Can someone explain why? Do I need to turn off a specific convention or change in the Fluent API? Is it really only looking at the column name?
[Table("Asset")]
public abstract class Asset
{
[Key]
public int AssetId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
[Table("Tank")]
public class Tank : Asset
{
public Tank()
{
this.TankCompnents = new Collection<TankComponent>();
}
public int TankField1 { get; set; }
public ICollection<TankComponent> TankCompnents { get; set; }
[NotMapped]
public IEnumerable<Floor> Floors { get { return this.TankCompnents.OfType<Floor>(); } }
}
[Table("TankComponent")]
public abstract class TankComponent
{
[Key]
public int TankComponentId { get; set; }
[ForeignKey("Tank")]
public int AssetId { get; set; }
public Tank Tank { get; set; }
public string Name { get; set; }
}
//forgot this in initial post
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Tank>()
.Map(m =>
{
m.Properties(a => new { a.AssetId, a.Name, a.Description });
m.Requires("AssetType").HasValue(1);
m.ToTable("Asset");
})
.Map(m =>
{
m.Properties(t => new { t.AssetId, t.TankField1 });
m.ToTable("Tank");
});
}
This mapping line...
m.Requires("AssetType").HasValue(1);
...and your comments seem to indicate that you possibly have a misunderstanding how Table-Per-Type (TPT) inheritance works.
EF does not need a specific column in the table of the base class Asset to detect what the actual type of the entity with a given primary key value is - unless you would use Table-Per-Hierarchy (TPH) inheritance mapping (i.e. a mapping without having [Table] attributes on your entities). For TPH a specific column - the discriminator - in indeed necessary to distinguish between the types because all properties of all entities in the inheritance tree would be stored in a single table. If you don't specify a discriminator explicitly - like AssetType - EF would create a column called Discriminator by default.
Now, TPT is a different story. If you query an entity that has other derived entities - for example...
var asset = context.Assets.First();
...EF will not only create a SQL query like SELECT TOP(1) * FROM ASSETS on the base table alone but instead a - possibly very complex - query with many LEFT OUTER JOINs to many other tables that belong to all possible derived entities. This query would either find a row in the Tank table or not. If it does find one EF will materialize a Tank object. If not it will materialize an Asset. (Cannot be the case here because Asset is abstract but assume for a moment it would not be abstract.) If Asset has other derived types EF will join their tables as well and decide again about the concrete entity type depending on the existence of joined rows.
So, with TPT the type is detected not by a special column but only by the result of (left outer) table joins.
The line above seems to confuse EF somehow. But it really doesn't belong into a TPT mapping and I would remove your whole mapping with Fluent API.
I've tested that the result is correct when you remove the mapping - i.e. the FK relationship will be created between TankComponent and Tank table (not Asset table).

Entity Framework Code First One-to-One Required-Required Relationship

When using Entity Framework Code First 4.3.1 it is possible to create relationships with a multiplicity of 1-to-1. That is, one entity on each end of the relationship.
It is possible to configure 1-to-1 relationships to be required-required or required-optional ^. However, when I switch between the two I do not see any differences in:
The database schema generated. I am targeting SQL Server 2008.
The runtime behaviour of EF.
As such, I am able to create a RequiredPrincipalAs record without a corresponding RequiredDependentAs record, despite the relationship being configured as required-required. This seems to contradict the documentation for HasRequired(...):
Configures a required relationship from this entity type. Instances of the entity type will not be able to be saved to the database unless this relationship is specified. The foreign key in the database will be non-nullable.
http://msdn.microsoft.com/en-us/library/gg671317
The required-required relationship entities:
public class RequiredPrincipalA
{
public int Id { get; set; }
public virtual RequiredDependentA DependentA { get; set; }
}
public class RequiredDependentA
{
public int Id { get; set; }
public virtual RequiredPrincipalA PrincipalA { get; set; }
}
The required-optional relationship entities:
public class RequiredPrincipalB
{
public int Id { get; set; }
public virtual OptionalDependentB DependentB { get; set; }
}
public class OptionalDependentB
{
public int Id { get; set; }
public virtual RequiredPrincipalB PrincipalB { get; set; }
}
The DbContext and model configuration:
public class AppContext : DbContext
{
public DbSet<RequiredPrincipalA> PrincipalAs { get; set; }
public DbSet<RequiredDependentA> DependentAs { get; set; }
public DbSet<RequiredPrincipalB> PrincipalBs { get; set; }
public DbSet<OptionalDependentB> DependentBs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<RequiredPrincipalA>()
.HasRequired(o => o.DependentA)
.WithRequiredPrincipal(o => o.PrincipalA);
modelBuilder.Entity<RequiredPrincipalB>()
.HasOptional(o => o.DependentB)
.WithRequired(o => o.PrincipalB);
}
}
The test code:
Database.SetInitializer(new DropCreateDatabaseAlways<AppContext>());
using (var ctx = new AppContext())
{
ctx.Database.Initialize(force: false);
ctx.PrincipalAs.Add(new RequiredPrincipalA());
ctx.PrincipalBs.Add(new RequiredPrincipalB());
ctx.SaveChanges();
}
I am aware I could add a [Required] data attribute to the navigation properties of RequiredPrincipalA.DependentA and RequiredDependentA.PrincipalA. This would cause EF validation to prevent the scenario above. However, I do not want to do this because it also validates the navigation property is populated when updating an existing entity. This means the application has to pre-fetch the entity at the other end of the relationship for every update.
Why do I not see any difference in the behaviour of EF just when changing a relationship between required-required and required-optional?
^ Note that optional-optional is also supported but this doesn't form part of my question. There are obvious differences in the generated database schema and runtime behaviour when an optional-optional relationship is configured.
I don't know why required-required is allowed for this case but it cannot exist in the database because relation is build on primary keys. Required-required means that A cannot be inserted if related B doesn't exist and B cannot be inserted if related A doesn't exist => neither A or B can be inserted.
Database relation has always principal and dependent entity - principal can always exist without dependent.
Real required-required in EF can be achieved only when both A and B are mapped to the same table (table splitting) because in such case they are both inserted with single insert command.
Not really an answer but I have more to say than will fit in comments. But you know, I write 900 page books...it's just how I roll. :)
Oddly I would expect the fluent configuration to behave the same way as the data annotation and am confused that it's not doing it. (I've pinged Rowan Miller with a link to this thread to get his feedback.) And the behavior I mean is: validating the constraint during SaveChanges.
On the database side, I'm with Ladislav.In the model, EF defines the 1:1 using the keys of the related entities. But in the database, you can't have FKs in both tables, so only the dependent table in the database will require that constraint that it's PK maps to an existing PK in the principal table.
And finally, I understand your reason for not wanting EF to enforce the relationship if you aren't going to always deal with teh full graph. I think 1:1 relationships are the most confusing of the EF relationship mappings and I always find myself having to go back for reminders of the rules and how things should work.
Old question. But since EF6 is still used and even available for .Net standard and this issue can be a real nuisance, I think it's worth mentioning something I couldn't find in other answers.
It is true that both HasRequired - WithRequiredPrincipal and HasOptional - WithRequired produce the same database schema and the same runtime behavior. That is, with both mappings it's possible to save a principal without a dependent entity and to remove the dependent later. So much for HasRequired.
But there is a way to make EF validate the required relationship when creating the entities, which is by simply adding a [Required] attribute:
public class RequiredPrincipalA
{
public int Id { get; set; }
[Required] // <== here
public virtual RequiredDependentA DependentA { get; set; }
}
public class RequiredDependentA
{
public int Id { get; set; }
public virtual RequiredPrincipalA PrincipalA { get; set; }
}
As said, only when creating the entities. It's still possible to set RequiredPrincipalA.RequiredDependentA = null and save it successfully. But I think that, fortunately, the likelihood of that happening in code is far lower than forgetting to set the required dependent.

EF Code First "Invalid column name 'Discriminator'" but no inheritance

I have a table in my database called SEntries (see below the CREATE TABLE statement). It has a primary key, a couple of foreign keys and nothing special about it. I have many tables in my database similar to that one, but for some reason, this table ended up with a "Discriminator" column on the EF Proxy Class.
This is how the class is declared in C#:
public class SEntry
{
public long SEntryId { get; set; }
public long OriginatorId { get; set; }
public DateTime DatePosted { get; set; }
public string Message { get; set; }
public byte DataEntrySource { get; set; }
public string SourceLink { get; set; }
public int SourceAppId { get; set; }
public int? LocationId { get; set; }
public long? ActivityId { get; set; }
public short OriginatorObjectTypeId { get; set; }
}
public class EMData : DbContext
{
public DbSet<SEntry> SEntries { get; set; }
...
}
When I try to add a new row to that table, I get the error:
System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.
This problem only occurs if you are inheriting your C# class from another class, but SEntry is not inheriting from anything (as you can see above).
In addition to that, once I get the tool-tip on the debugger when I mouse over the EMData instance for the SEntries property, it displays:
base {System.Data.Entity.Infrastructure.DbQuery<EM.SEntry>} = {SELECT
[Extent1].[Discriminator] AS [Discriminator],
[Extent1].[SEntryId] AS [SEntryId],
[Extent1].[OriginatorId] AS [OriginatorId],
[Extent1].[DatePosted] AS [DatePosted],
[Extent1].[Message] AS [Message],
[Extent1].[DataEntrySource] AS [DataE...
Any suggestions or ideas where to get to the bottom of this issue? I tried renaming the table, the primary key and a few other things, but nothing works.
SQL-Table:
CREATE TABLE [dbo].[SEntries](
[SEntryId] [bigint] IDENTITY(1125899906842624,1) NOT NULL,
[OriginatorId] [bigint] NOT NULL,
[DatePosted] [datetime] NOT NULL,
[Message] [nvarchar](500) NOT NULL,
[DataEntrySource] [tinyint] NOT NULL,
[SourceLink] [nvarchar](100) NULL,
[SourceAppId] [int] NOT NULL,
[LocationId] [int] NULL,
[ActivityId] [bigint] NULL,
[OriginatorObjectTypeId] [smallint] NOT NULL,
CONSTRAINT [PK_SEntries] PRIMARY KEY CLUSTERED
(
[SEntryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[SEntries] WITH CHECK ADD CONSTRAINT [FK_SEntries_ObjectTypes] FOREIGN KEY([OriginatorObjectTypeId])
REFERENCES [dbo].[ObjectTypes] ([ObjectTypeId])
GO
ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_ObjectTypes]
GO
ALTER TABLE [dbo].[SEntries] WITH CHECK ADD CONSTRAINT [FK_SEntries_SourceApps] FOREIGN KEY([SourceAppId])
REFERENCES [dbo].[SourceApps] ([SourceAppId])
GO
ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_SourceApps]
GO
Turns out that Entity Framework will assume that any class that inherits from a POCO class that is mapped to a table on the database requires a Discriminator column, even if the derived class will not be saved to the DB.
The solution is quite simple and you just need to add [NotMapped] as an attribute of the derived class.
Example:
class Person
{
public string Name { get; set; }
}
[NotMapped]
class PersonViewModel : Person
{
public bool UpdateProfile { get; set; }
}
Now, even if you map the Person class to the Person table on the database, a "Discriminator" column will not be created because the derived class has [NotMapped].
As an additional tip, you can use [NotMapped] to properties you don't want to map to a field on the DB.
Here is the Fluent API syntax.
http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName {
get {
return this.FirstName + " " + this.LastName;
}
}
}
class PersonViewModel : Person
{
public bool UpdateProfile { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ignore a type that is not mapped to a database table
modelBuilder.Ignore<PersonViewModel>();
// ignore a property that is not mapped to a database column
modelBuilder.Entity<Person>()
.Ignore(p => p.FullName);
}
I just encountered this and my problem was caused by having two entities both with the System.ComponentModel.DataAnnotations.Schema.TableAttribute referring to the same table.
for example:
[Table("foo")]
public class foo
{
// some stuff here
}
[Table("foo")]
public class fooExtended
{
// more stuff here
}
changing the second one from foo to foo_extended fixed this for me and I'm now using Table Per Type (TPT)
I had a similar problem, not exactly the same conditions and then i saw this post. Hope it helps someone. Apparently i was using one of my EF entity models a base class for a type that was not specified as a db set in my dbcontext. To fix this issue i had to create a base class that had all the properties common to the two types and inherit from the new base class among the two types.
Example:
//Bad Flow
//class defined in dbcontext as a dbset
public class Customer{
public int Id {get; set;}
public string Name {get; set;}
}
//class not defined in dbcontext as a dbset
public class DuplicateCustomer:Customer{
public object DuplicateId {get; set;}
}
//Good/Correct flow*
//Common base class
public class CustomerBase{
public int Id {get; set;}
public string Name {get; set;}
}
//entity model referenced in dbcontext as a dbset
public class Customer: CustomerBase{
}
//entity model not referenced in dbcontext as a dbset
public class DuplicateCustomer:CustomerBase{
public object DuplicateId {get; set;}
}
Another scenario where this occurs is when you have a base class and one or more subclasses, where at least one of the subclasses introduce extra properties:
class Folder {
[key]
public string Id { get; set; }
public string Name { get; set; }
}
// Adds no props, but comes from a different view in the db to Folder:
class SomeKindOfFolder: Folder {
}
// Adds some props, but comes from a different view in the db to Folder:
class AnotherKindOfFolder: Folder {
public string FolderAttributes { get; set; }
}
If these are mapped in the DbContext like below, the "'Invalid column name 'Discriminator'" error occurs when any type based on Folder base type is accessed:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Folder>().ToTable("All_Folders");
modelBuilder.Entity<SomeKindOfFolder>().ToTable("Some_Kind_Of_Folders");
modelBuilder.Entity<AnotherKindOfFolder>().ToTable("Another_Kind_Of_Folders");
}
I found that to fix the issue, we extract the props of Folder to a base class (which is not mapped in OnModelCreating()) like so - OnModelCreating should be unchanged:
class FolderBase {
[key]
public string Id { get; set; }
public string Name { get; set; }
}
class Folder: FolderBase {
}
class SomeKindOfFolder: FolderBase {
}
class AnotherKindOfFolder: FolderBase {
public string FolderAttributes { get; set; }
}
This eliminates the issue, but I don't know why!
I get the error in another situation, and here are the problem and the solution:
I have 2 classes derived from a same base class named LevledItem:
public partial class Team : LeveledItem
{
//Everything is ok here!
}
public partial class Story : LeveledItem
{
//Everything is ok here!
}
But in their DbContext, I copied some code but forget to change one of the class name:
public class MFCTeamDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Other codes here
modelBuilder.Entity<LeveledItem>()
.Map<Team>(m => m.Requires("Type").HasValue(ItemType.Team));
}
public class ProductBacklogDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Other codes here
modelBuilder.Entity<LeveledItem>()
.Map<Team>(m => m.Requires("Type").HasValue(ItemType.Story));
}
Yes, the second Map< Team> should be Map< Story>.
And it cost me half a day to figure it out!
Old Q, but for posterity...it also also happens (.NET Core 2.1) if you have a self-referencing navigation property ("Parent" or "Children" of the same type) but the Id property name isn't what EF expects. That is, I had an "Id" property on my class called WorkflowBase, and it had an array of related child steps, which were also of type WorkflowBase, and it kept trying to associate them with a non-existent "WorkflowBaseId" (the name i suppose it prefers as a natural/conventional default). I had to explicitly configure it using HasMany(), WithOne(), and HasConstraintName() to tell it how to traverse. But I spent a few hours thinking the problem was in 'locally' mapping the object's primary key, which i attempted to fix a bunch of different ways but which was probably always working.
this error happen with me because I did the following
I changed Column name of table in database
(I did not used Update Model from database in Edmx) I Renamed manually Property name to match the change in database schema
I did some refactoring to change name of the property in the class to be the same as database schema and models in Edmx
Although all of this, I got this error
so what to do
I Deleted the model from Edmx
Right Click and Update Model from database
this will regenerate the model, and entity framework will not give you this error
hope this help you