بررسی تفصیلی رابطه Many-to-Many در EF Code first
نویسنده: وحید نصیری
تاریخ: ۱۳۹۱/۱۲/۰۴ ۸:۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Data.Entity.ModelConfiguration;
namespace Sample
{
public class BlogPost
{
public int Id { set; get; }
[StringLength(maximumLength: 450, MinimumLength = 1), Required]
public string Title { set; get; }
[MaxLength]
public string Body { set; get; }
public virtual ICollection<Tag> Tags { set; get; } // many-to-many
public BlogPost()
{
Tags = new List<Tag>();
}
}
public class Tag
{
public int Id { set; get; }
[StringLength(maximumLength: 450), Required]
public string Name { set; get; }
public virtual ICollection<BlogPost> BlogPosts { set; get; } // many-to-many
public Tag()
{
BlogPosts = new List<BlogPost>();
}
}
public class MyContext : DbContext
{
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<Tag> Tags { get; set; }
}
public class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(MyContext context)
{
var tag1 = new Tag { Name = "Tag1" };
context.Tags.Add(tag1);
var post1 = new BlogPost { Title = "Title...1", Body = "Body...1" };
context.BlogPosts.Add(post1);
post1.Tags.Add(tag1);
base.Seed(context);
}
}
public static class Test
{
public static void RunTests()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
using (var ctx = new MyContext())
{
var post1 = ctx.BlogPosts.Find(1);
if (post1 != null)
{
Console.WriteLine(post1.Title);
}
}
}
}
} public class TagMap : EntityTypeConfiguration<Tag>
{
public TagMap()
{
this.HasMany(x => x.BlogPosts)
.WithMany(x => x.Tags)
.Map(map =>
{
map.MapLeftKey("TagId");
map.MapRightKey("BlogPostId");
map.ToTable("BlogPostsJoinTags");
});
}
}
public class MyContext : DbContext
{
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TagMap());
base.OnModelCreating(modelBuilder);
}
} using (var ctx = new MyContext())
{
var post1 = ctx.BlogPosts.Find(1);
if (post1 != null)
{
Console.WriteLine(post1.Title);
foreach (var tag in post1.Tags.ToList())
post1.Tags.Remove(tag);
ctx.SaveChanges();
}
} var post1 = ctx.BlogPosts.Find(1);
if (post1 != null)
{
ctx.BlogPosts.Remove(post1);
ctx.SaveChanges();
} var post1 = ctx.BlogPosts.Find(1);
if (post1 != null)
{
var tag2 = new Tag { Name = "Tag2" };
post1.Tags.Add(tag2);
ctx.SaveChanges();
} //نام تگهای دریافتی از کاربر
var tagsList = new[] { "Tag1", "Tag2", "Tag3" };
//بارگذاری یک مطلب به همراه تگهای آن
var post1 = ctx.BlogPosts.Include(x => x.Tags).FirstOrDefault(x => x.Id == 1);
if (post1 != null)
{
//ابتدا کلیه تگهای موجود را حذف خواهیم کرد
if (post1.Tags != null && post1.Tags.Any())
post1.Tags.Clear();
//سپس در طی فقط یک کوئری بررسی میکنیم کدامیک از موارد ارسالی موجود هستند
var listOfActualTags = ctx.Tags.Where(x => tagsList.Contains(x.Name)).ToList();
var listOfActualTagNames = listOfActualTags.Select(x => x.Name.ToLower()).ToList();
//فقط موارد جدید به تگها و ارتباطات موجود اضافه میشوند
foreach (var tag in tagsList)
{
if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
{
ctx.Tags.Add(new Tag { Name = tag.Trim() });
}
}
ctx.SaveChanges(); // ثبت موارد جدید
//موارد قبلی هم حفظ میشوند
foreach (var item in listOfActualTags)
{
post1.Tags.Add(item);
}
ctx.SaveChanges();
}SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name] FROM [dbo].[Tags] AS [Extent1] WHERE [Extent1].[Name] IN (N'Tag1',N'Tag2',N'Tag3')
ctx.BlogPosts.Where(p => p.Id == 1).Include(p => p.Tags).FirstOrDefault()
var posts = from p in ctx.BlogPosts
from t in p.Tags
where t.Name == "Tag1"
select p;var posts = ctx.Tags.Where(x => x.Name == "Tag1").SelectMany(x => x.BlogPosts);
post1.Tags.Add(tag);
//فقط موارد جدید به تگها و ارتباطات موجود اضافه میشوند
foreach (var tag in data.Tags)
{
if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
{
_tag.Add(new Tag { Title = tag.Trim() });
}
}
_uow.SaveChanges(); // ثبت موارد جدیدif (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
{
var tags = new Tag { Title = tag.Trim() };
_tag.Add(tags);
posts.Tags.Add(tags);
}var newTag = ctx.Tags.Add(new Tag { Name = tag.Trim() });
post1.Tags.Add(newTag);public class Person
{
//...
public virtual IList<Center> PreferedCenters { get; set; }
public virtual IList<Center> ActiveCenters { get; set; }
public Person()
{
PreferedCenters = new List<Center>();
ActiveCenters = new List<Center>();
}
} public class Center
{
//...
public virtual IList<Person> Persons { get; set; }
public Center()
{
Persons = new List<Person>();
}
} An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll Additional information: Multiplicity constraint violated. The role 'Center_Persons_Source' of the relationship 'Yarigaran.DataLayer.Center_Persons' has multiplicity 1 or 0..1.
modelBuilder.Entity<Person>()
.HasMany(u => u.PreferedCenters)
.WithMany(t => t.Persons)
.Map(x =>
{
x.MapLeftKey("PersonId");
x.MapRightKey("CenterId");
x.ToTable("Center_Persons1"); // جدول واسط یک
});
modelBuilder.Entity<Person>()
.HasMany(u => u.ActiveCenters)
.WithMany(t => t.Persons)
.Map(x =>
{
x.MapLeftKey("PersonId");
x.MapRightKey("CenterId");
x.ToTable("Center_Persons2"); // جدول واسط دو
}); public class EfTagService : ITagService
{
IUnitOfWork _uow;
readonly IDbSet<Tag> _tags;
public EfTagService(IUnitOfWork uow)
{
_uow = uow;
_tags = _uow.Set<Tag>();
}
public bool CreateTag(Tag tag)
{
// ...
}
public List<Tag> GetTagsByName(string[] tagNames)
{
// return ...
}
} public class EfPostService : IPostService
{
IUnitOfWork _uow;
readonly IDbSet<Post> _posts;
//این قسمت
private EfTagService _tagService;
public EfPostService(IUnitOfWork uow)
{
_uow = uow;
_posts = uow.Set<Post>();
//این قسمت
_tagService = new EfTagService(_uow);
}
public void AddTagsToPost(Post post, string[] tagsList)
{
if (post.Tags != null && post.Tags.Any())
post.Tags.Clear();
//این قسمت
var listOfActualTags = _tagService.GetTagsByName(tagsList);
var listOfActualTagNames = listOfActualTags.Select(x => x.Name.ToLower()).ToList();
foreach (var tag in tagsList)
{
if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
{
Tag newTag = new Tag() { Name = tag };
//این قسمت
_tagService.CreateTag(newTag);
post.Tags.Add(newTag);
}
}
// ...
}
} public EfPostService(IUnitOfWork uow, ITagService tagService)
public class AA
{
public virtual ICollection<CC> Cs { get; set; }
}
public class BB
{
public virtual ICollection<CC> Cs { get; set; }
}
public class CC
{
public virtual AA AA { get; set; }
public virtual long AAId { get; set; }
public virtual BB BB { get; set; }
public virtual long BBId { get; set; }
public virtual string Value{get;set}
}
var usersWithoutUnits = ctx.Users.Where(x => !x.UsersJoinUnits.Any(y => y.UserId == x.UserId)).ToList();