EF4 CTP5 Database First + Many-To-Many Relation (Error) - entity-framework

I'm pretty sure it's something regarding hidden conventions, but I always get an error when trying to map a many-to-many relation to an existing database.
Here is the simplest example:
[Table("ALRole", SchemaName = "AL")]
public class Role
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
[Table("ALUser", SchemaName = "AL")]
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
I got the usual three tables in the db: the first two are obvious, and the third is created with this script:
CREATE TABLE AL.ALUsersRoles
(
RoleID int NOT NULL,
UserID int NOT NULL,
CONSTRAINT PK_ALUserRole PRIMARY KEY(RoleID, UserID),
CONSTRAINT FK_ALUserRole_RoleID FOREIGN KEY(RoleID) REFERENCES AL.ALRole(ID),
CONSTRAINT FK_ALUserRole_UserID FOREIGN KEY(UserID) REFERENCES AL.ALUser(ID)
)
Now I try to map the many-to-many relation, with code like this:
// ...I'm in the EntityTypeConfiguration-derived class (User)
HasMany(u => u.Roles)
.WithMany(r => r.Users)
.Map(m =>
{
m.MapLeftKey(u => u.ID, "UserID");
m.MapRightKey(r => r.ID, "RoleID");
ToTable("ALUsersRoles", "AL");
});
I tried all the possibile combinations and variations in this code, but I always get the error:
{"Invalid column name 'Name'.\r\nInvalid ...and so on...
So I think it must be the table that is not created correctly.
Any ideas?
Thanks in advance
Andrea
P.S.: I stripped down some of my code, so maybe there can be some small typo...

well, this works for me same as OP.
//many-to-many between *Users -> Web_User_Rol <- Web_Rol*
modelBuilder.Entity<Users>()
.HasMany(u => u.Web_Rols).WithMany(r => r.Users)
.Map(t=>t.MapLeftKey("user_id")
.MapRightKey("roleID")
.ToTable("Web_User_Rol"));

There is nothing wrong with your object model or fluent API code. I've used them and they perfectly created the desired schema without any exception. I think your problem comes from another entity (perhaps one with a "Name" property) unrelated to what you've shown here. To find that, drop (or rename) your existing database and let Code First create one for you and then compare the 2 databases and see what is different.

Related

Many to Many between IdentityUser and other table in a separate context

I am having difficulty creating a join table relationship between my Identity Framework IdentityContext(the IdentityUser) and one of my other tables Let's call it Entry. The problem is, Entry is in an entirely separate context doing it's own thing as well.
What is the proper way to associate these two? Where do I define the Join Table in fluent api?
Right now, I am getting the following error.
The key {'ApplicationUserId'} contains properties in shadow state and is referenced by a relationship from 'ApplicationUser.ApplicationUserEntries' to 'ApplicationUserEntry.ApplicationUser'. Configure a non-shadow principal key for this relationship.
These are how my tables are defined.
public class ApplicationUser : IdentityUser
{
...
public virtual List<ApplicationUserEntry> ApplicationUserEntries { get; set; }
}
public class Entry
{
public int Id { get; set; }
...
public virtual List<ApplicationUserEntry> ApplicationUserEntries { get; set; }
}
And the join table as follows.
public class ApplicationUserEntry
{
public int ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public int EntryId { get; set; }
public Entry Entry { get; set; }
}
For the IdentityContext I have just some generic setup for other properties
var users = modelBuilder.Entity<ApplicationUser>();
users.Property(u => u.Name).IsRequired().HasMaxLength(65);
users.Property(u => u.FirstName).HasMaxLength(32);
users.Property(u => u.LastName).HasMaxLength(32);
And in my GoalsContext I have some general setup for other unrelated stuff, and the join table defined for ApplicationUserEntry
// Entry Configuration
var entries = modelBuilder.Entity<Entry>();
entries.HasKey(e => e.Id);
entries.HasAlternateKey(e => new { e.MilestoneId, e.CategoryId, e.MetricId });
entries.Property(e => e.Value).IsRequired();
entries.Property(e => e.Locked).IsRequired().HasDefaultValue(false);
entries.ToTable("GoalsEntries");
// ApplicationUserEntry Join Table
modelBuilder.Entity<ApplicationUserEntry>()
.ToTable("GoalsApplicationUserEntry")
.HasKey(se => new { se.ApplicationUserId, se.EntryId });
modelBuilder.Entity<ApplicationUserEntry>()
.HasOne(se => se.ApplicationUser)
.WithMany(s => s.ApplicationUserEntries)
.HasForeignKey(se => se.ApplicationUserId);
modelBuilder.Entity<ApplicationUserEntry>()
.HasOne(se => se.Entry)
.WithMany(e => e.ApplicationUserEntries)
.HasForeignKey(se => se.EntryId);
Now I'm sure I'm obviously missing something but I can't figure out what. I've never attempted to create a many to many relationship between two tables that are defined in two different contexts... and not even sure if that's wise or not to do.
My ultimate goal is to be able to associate owners with Entry records, so they can only be modified by the owners, which I verify with Identity Framework.
Ideally I would just prefer a unidirectional relationship, so I can find the owner from the Entry, but I'm not intending to get a list of Entry by looking at the IdentityUser

EF Code first and optional:optional relationship

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.

Mapping twitter style followers following relationship in EF Code First

I want to be able to access followers and following as collections from my user entity:
public class User
{
public int Id { get; set; }
public ICollection<User> Followers { get; set; }
public ICollection<User> Following { get; set; }
}
This would then map to a table:
UserFollowers(UserId, FollowerId)
I can get the table generated correctly and working for followers with some fluent config:
modelBuilder.Entity<User>().HasMany(m => m.Followers).WithMany().Map(x => x.MapLeftKey("UserId").MapRightKey("FollowerId").ToTable("UserFollowers"));
The tricky part is letting EF know that the Following collection should map to the same table but with FollowerId mapping to the User.
I have tried simply adding:
modelBuilder.Entity<User>().HasMany(m => m.Following).WithMany().Map(x => x.MapLeftKey("FollowerId").MapRightKey("UserId").ToTable("UserFollowers"));
but I get an error:
The EntitySet 'UserUser1' with schema 'dbo' and table 'UserFollowers'
was already defined. Each EntitySet must refer to a unique schema and
table.
How do I resolve this?
you can do this using one mapping like this.
modelBuilder.Entity<User>().HasMany(m => m.Followers).WithMany(m=>m.Following ).Map(x => x.MapLeftKey("UserId").MapRightKey("FollowerId").ToTable("UserFollowers"));

EF 4 Code First - Combine Views and Tables

I researched this question for days and cannot seem to find an option I feel good about; however, here is a link to a very similar question:
Add Calculated field to Model
Ultimately, I have the same question, but I am hoping for a better solution.
Consider the following DB Tables:
CREATE TABLE [Contact](
[ContactID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[ContactName] [varchar](80) NOT NULL,
[Email] [varchar](80) NOT NULL,
[Title] [varchar](120) NOT NULL,
[Address1] [varchar](80) NOT NULL,
[Address2] [varchar](80) NOT NULL,
[City] [varchar](80) NOT NULL,
[State_Province] [varchar](50) NOT NULL,
[ZIP_PostalCode] [varchar](30) NOT NULL,
[Country] [varchar](50) NOT NULL,
[OfficePhone] [varchar](30) NOT NULL,
[MobilePhone] [varchar](30) NOT NULL)
CREATE TABLE [Blog](
[BlogID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[BlogName] [varchar](80) NOT NULL,
[CreatedByID] [int] NOT NULL, -- FK to ContactTable
[ModifiedByID] [int] NOT NULL -- FK to ContactTable
)
CREATE TABLE [Post](
[PostID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[BlogID] [int] NOT NULL, -- FK to BlogTable
[Entry] [varchar](8000) NOT NULL,
[CreatedByID] [int] NOT NULL, -- FK to ContactTable
[ModifiedByID] [int] NOT NULL -- FK to ContactTable
)
I now would like to use views for loading "common" lookup/calculated info. Every time we display a post on the site, we want to know the name of the person who created the post and who last modified it. These are two fields that are stored in separate tables from the post table. I could easily use the following syntax (assuming Lazy/eager loading was applied and CreatedBy was a property, of type Contact, based on CreatedByID): currentPost.CreatedBy.Name;
The problem with that approach is the number of Db calls and also the large record retrieved for contact, but we are only using Name 99% in this situation. I realize the DB schema above is tiny, but this is just a simplified example and the real contact table has about 50 fields.
To manage this type of situation in the past (prior to using EF), I have typically built out "detail" views for the tables I will use. The "detail" views contain common lookup/calculated fields so that it only takes 1 call to the DB to efficiently get all the info I need (NOTE: We also use indexing on our SQL views to make this extremely efficient for reading) Here is a list of views that I will commonly use (as they will contain "look up" fields from related tables):
ALTER VIEW [icoprod].[BlogDetail]
AS
SELECT B.[BlogID],
B.[BlogName],
B.[BlogDescription],
B.[CreatedByID],
B.[ModifiedByID],
CREATEDBY.[ContactName] AS CreatedByName,
MODIFIEDBY.[ContactName] AS ModifiedByName,
(SELECT COUNT(*) FROM Post P WHERE P.BlogID = B.BlogID) AS PostCount
FROM Blog AS B
JOIN Contact AS CREATEDBY ON B.CreatedByID = CREATEDBY.ContactID
JOIN Contact AS MODIFIEDBY ON B.ModifiedByID = MODIFIEDBY.ContactID
ALTER VIEW [icoprod].[PostDetail]
AS
SELECT P.[PostID],
P.[BlogID],
P.[Entry],
P.[CreatedByID],
P.[ModifiedByID],
CREATEDBY.[ContactName] AS CreatedByName,
MODIFIEDBY.[ContactName] AS ModifiedByName,
B.Name AS BlogName
FROM Post AS P
JOIN Contact AS CREATEDBY ON P.CreatedByID = CREATEDBY.ContactID
JOIN Contact AS MODIFIEDBY ON P.ModifiedByID = MODIFIEDBY.ContactID
JOIN Blog AS B ON B.BlogID = P.BlogID
Here is an overview of my "POCO" objects:
public class Blog
{
public int ID { get; set; }
public string Name { get; set; }
public int CreatedByID { get; set; }
public DateTime ModifiedByID { get; set; }
}
public class Post
{
public int ID { get; set; }
public string Name { get; set; }
public int CreatedByID { get; set; }
public DateTime ModifiedByID { get; set; }
}
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Title { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string MobilePhone { get; set; }
}
public class BlogDetails : Blog
{
public string CreatedByName { get; set; }
public string ModifiedByName { get; set; }
public int PostsCount { get; set; }
}
public class PostDetails : Post
{
public string CreatedByName { get; set; }
public string ModifiedByName { get; set; }
public string BlogName { get; set; }
}
The reason I like this approach is that it allows me to retrieve information from the database based on tables or views AND if I load a view, the view contains all the "table" information which would allow me to load from a view but save to a table. IMO, this gives me the best of both worlds.
I have used this approach in the past, but typically, I just loaded information from the DB using datarows or info from stored procs or even used subsonic activerecord pattern and mapped fields after loading from the DB. I am really hoping I can do something in EF that lets me load these objects without creating another layer of abstraction.
Here is what I have tried to use for configuration (using Fluent API and code-first EF):
public class PostConfiguration : EntityTypeConfiguration<Post>
{
public PostConfiguration()
: base()
{
HasKey(obj => obj.ID);
Property(obj => obj.ID).
HasColumnName("PostID").
HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
IsRequired();
Map(m =>
{
m.ToTable("Post");
});
}
}
public class BlogConfiguration : EntityTypeConfiguration<Blog>
{
public BlogConfiguration()
: base()
{
HasKey(obj => obj.ID);
Property(obj => obj.ID).
HasColumnName("BlogID").
HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
IsRequired();
Map(m =>
{
m.ToTable("Blog");
});
}
}
public class ContactConfiguration : EntityTypeConfiguration<Contact>
{
public ContactConfiguration()
: base()
{
HasKey(obj => obj.ID);
Property(obj => obj.ID).
HasColumnName("ContactID").
HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
IsRequired();
Map(m =>
{
m.ToTable("Contact");
});
}
}
public class PostDetailsConfiguration : EntityTypeConfiguration<PostDetails>
{
public PostDetailsConfiguration()
: base()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("icoprod.PostDetails");
});
}
}
public class BlogDetailsConfiguration : EntityTypeConfiguration<BlogDetails>
{
public BlogDetailsConfiguration()
: base()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("icoprod.BlogDetails");
});
}
}
At this point, I have tried to use a view containing all of the information from the table with "extended" information and when I try this I get the dreaded 3032 error (error sample here). Then I tried to have the view ONLY contain the Primary key of the table and the "extended" properties (e.g. [Entry] is not in PostDetails view). When I try this, I get the following error:
All objects in the EntitySet 'DBContext.Post' must have unique primary keys. However, an instance of type 'PostDetails' and an instance of type 'Post' both have the same primary key value, 'EntitySet=Post;ID=1'.
So I have played with leaving off MapInheritedProperties a bit, but with no luck. I continue to get a similar error.
Does anyone have a suggestion on how to "extend" a base/table object and load info from a view? Again, I believe there is a big performance gain by doing this. The article I referenced at the beginning of this question has 2 potential solutions, but 1 requires too many DB hits (just to get some common lookup info) and the other requires an additional layer of abstraction (and I would really like to go directly to my POCO's from the DB, without writing any mapping).
Lastly, thank you to everyone who answers these types of questions. I applaud everyone who has contributed to responses over the years. I think too many of us developers take this information for granted!!
Loading record from view and saving it to table will not work with code mapping - Blog entity will always be loaded from table and saved to table and BlogDetail entity will always be loaded from view and saved to view - so you must have updatable view or instead of trigger to support this scenario. If you use EDMX you can also map custom SQL / Stored procedure executed for insert, update and delete to force saving to table but this feature is not available in code mapping. Anyway it is not your biggest problem.
You can use your view and you can map it to class as you did but you must not map the inheritance. The reason is the way how inheritance works. Inheritance says that entity is either parent or child (which can act as parent). There can never be database record which can be be both parent (I mean only parent) or child. It is even not possible in .NET because to support this scenario you need two instances - on of parent type and one of child type. These two instances are not equivalent because pure parent cannot be cast to child (it is not a child). And here comes the biggest problem. Once you map inheritance the key must be unique in the whole inheritance hierarchy. So you can never have two instances (one for parent and one for child) with the same key.
As a workaround don't derive BlogDetail from mapped entity (Blog). Either use third not mapped class as parent for both or interface. Also don't use MapInheritedProperties to make your BlogDetail completely unrelated to Blog.
Another workaround is not mapping BlogDetail at all. In such case you can use your code as is and instead of using a view create simple reusable query with projection:
var blogDetails = from b in context.Blogs
where ...
select new BlogDetail
{
Name = b.Name,
CreatedByID = b.CreatedByID,
...
CreatedByName = b.CreatedBy.Name // You need navigation property
...
};
In both cases if you need to save Blog you must create new instance and fill it from BlogDetail. After that you attach it to context, set it to modified state and save changes.

Mapping properties to (differently named) foreign key fields in Entity Framework CTP5

I'm trying to use the Entity Framework CTP5 Fluent API to map an exist database. I have the following classes:
public class Shop
{
public long Id
{
get;
set;
}
}
public class Sale
{
public long Id
{
get;
set;
}
public virtual Shop Shop
{
get;
set;
}
}
The corresponding tables are called "Stores" and "Sales". Sales has a StoreId foreign key that points to the Id field in the Stores table.
I'm struggling to map the Sale.Shop.Id to the StoreId in the table. I'm not at liberty to change it to ShopId, so need to map it.
In CTP4, I was using:
modelBuilder.Entity<Sale>().MapSingleType(x =>
new
{
Id = x.Id,
StoreId = x.Shop.Id
});
I tried the following:
modelBuilder.Entity<Sale>().Property(x => x.Shop.Id).HasColumnName("StoreId");
However, it seems this only works with a primitive type.
How do I specify this mapping?
Update: I've added a revised version for the Release Candidate of EF 4.1 below
After some hunting, I've found the answer that works for me:
EF4.1 RC version:
modelBuilder.Entity<Booking>().HasRequired(b => b.Booker)
.WithMany(m => m.BookedSlots).Map(p=>{
p.MapKey("BookerID");
});
in your case:
modelBuilder.Entity<Sale>().HasRequired(sale => sale.Shop)
.WithMany().Map(s=> {
s.MapKey("StoreId");
});
My version is slightly different because I have navigation properties on both sides of the relationship.
I think the best way to solve this would be to upgrade your independent Association to be a Foreign Key Association meaning that instead of hiding the foreign key ShopId, actually including it in Sale class. Then you can use Data Aannotations/Fluent API to change its column name to match to your existing schema:
public class Shop
{
public long Id { get;set; }
}
public class Sale
{
public long Id { get; set; }
[Column(Name="StoreID")]
public long ShopId { get; set; }
public virtual Shop Shop { get; set; }
}
Which results to the desired DB Schema:
I think what you're looking for is the RelatedTo attribute. More information in this ADO.NET team blog post.