EF Code First #7
نویسنده: وحید نصیری
تاریخ: ۱۳۹۱/۰۲/۲۰ ۱۱:۰۱:۰۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
public int Id { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
public virtual AlimentaryHabits AlimentaryHabits { set; get; }
public virtual ICollection<CustomerAlias> Aliases { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual Address Address { get; set; }
}
}
namespace EF_Sample35.Models
{
public class CustomerAlias
{
public int Id { get; set; }
public string Aka { get; set; }
public virtual Customer Customer { get; set; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Role
{
public int Id { set; get; }
public string Name { set; get; }
public virtual ICollection<Customer> Customers { set; get; }
}
}
namespace EF_Sample35.Models
{
public class AlimentaryHabits
{
public int Id { get; set; }
public bool LikesPasta { get; set; }
public bool LikesPizza { get; set; }
public int AverageDailyCalories { get; set; }
public virtual Customer Customer { get; set; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Address
{
public int Id { set; get; }
public string City { set; get; }
public string StreetAddress { set; get; }
public string PostalCode { set; get; }
public virtual ICollection<Customer> Customers { set; get; }
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerAliasConfig : EntityTypeConfiguration<CustomerAlias>
{
public CustomerAliasConfig()
{
// one-to-many
this.HasRequired(x => x.Customer)
.WithMany(x => x.Aliases)
.WillCascadeOnDelete();
}
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// one-to-one
this.HasOptional(x => x.AlimentaryHabits)
.WithRequired(x => x.Customer)
.WillCascadeOnDelete();
// many-to-many
this.HasMany(p => p.Roles)
.WithMany(t => t.Customers)
.Map(mc =>
{
mc.ToTable("RolesJoinCustomers");
mc.MapLeftKey("RoleId");
mc.MapRightKey("CustomerId");
});
// many-to-one
this.HasOptional(x => x.Address)
.WithMany(x => x.Customers)
.WillCascadeOnDelete();
}
}
}
using System.Data.Entity;
using System.Data.Entity.Migrations;
using EF_Sample35.Mappings;
using EF_Sample35.Models;
namespace EF_Sample35.DataLayer
{
public class Sample35Context : DbContext
{
public DbSet<AlimentaryHabits> AlimentaryHabits { set; get; }
public DbSet<Customer> Customers { set; get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerConfig());
modelBuilder.Configurations.Add(new CustomerAliasConfig());
base.OnModelCreating(modelBuilder);
}
}
public class Configuration : DbMigrationsConfiguration<Sample35Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(Sample35Context context)
{
base.Seed(context);
}
}
}
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual AlimentaryHabits AlimentaryHabits { set; get; }
}
}
namespace EF_Sample35.Models
{
public class AlimentaryHabits
{
// ...
public virtual Customer Customer { get; set; }
}
}
Unable to determine the principal end of an association between
the types 'EF_Sample35.Models.Customer' and 'EF_Sample35.Models.AlimentaryHabits'.
The principal end of this association must be explicitly configured using either
the relationship fluent API or data annotations.
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// one-to-one
this.HasOptional(x => x.AlimentaryHabits)
.WithRequired(x => x.Customer)
.WillCascadeOnDelete();
}
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual ICollection<CustomerAlias> Aliases { get; set; }
}
}
namespace EF_Sample35.Models
{
public class CustomerAlias
{
// ...
public virtual Customer Customer { get; set; }
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerAliasConfig : EntityTypeConfiguration<CustomerAlias>
{
public CustomerAliasConfig()
{
// one-to-many
this.HasRequired(x => x.Customer)
.WithMany(x => x.Aliases)
.WillCascadeOnDelete();
}
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Role
{
// ...
public virtual ICollection<Customer> Customers { set; get; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// ...
public virtual ICollection<Role> Roles { get; set; }
}
}
CREATE TABLE [dbo].[RolesJoinCustomers](
[RoleId] [int] NOT NULL,
[CustomerId] [int] NOT NULL,
)
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// many-to-many
this.HasMany(p => p.Roles)
.WithMany(t => t.Customers)
.Map(mc =>
{
mc.ToTable("RolesJoinCustomers");
mc.MapLeftKey("RoleId");
mc.MapRightKey("CustomerId");
});
}
}
}
namespace EF_Sample35.Models
{
public class Address
{
public int Id { set; get; }
public string City { set; get; }
public string StreetAddress { set; get; }
public string PostalCode { set; get; }
}
}
using System.Collections.Generic;
namespace EF_Sample35.Models
{
public class Customer
{
// …
public virtual Address Address { get; set; }
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample35.Models;
namespace EF_Sample35.Mappings
{
public class CustomerConfig : EntityTypeConfiguration<Customer>
{
public CustomerConfig()
{
// many-to-one
this.HasOptional(x => x.Address)
.WithMany(x => x.Customers)
.WillCascadeOnDelete();
}
}
}
[HttpPost]
public ActionResult Edit(User user, string[] tags)
{
if (ModelState.IsValid)
{
List<Role> roles = new List<Role>();
foreach (var item in tags)
{
Role role = db.Roles.Find(long.Parse(item));
roles.Add(role);
}
user.Roles = roles;
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
if(user.Roles != null && user.Roles.Any()) user.Roles.Clear();
ctx.Roles.Attach(new Role { Id = item });
[HttpPost]
public ActionResult Edit(User user, string[] tags)
{
User Currentuser = db.Users.Find(user.Id);
Currentuser.FirstName = user.FirstName;
Currentuser.LastName = user.LastName;
if (ModelState.IsValid)
{
List<Role> roles = new List<Role>();
if (Currentuser.Roles != null && Currentuser.Roles.Any())
Currentuser.Roles.Clear();
foreach (var item in tags)
{
Role role = db.Roles.Find(long.Parse(item));
roles.Add(role);
}
Currentuser.Roles = roles;
db.Entry(Currentuser).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Currentuser);
}
var listOfActualRoles = db.Roles.Where(x => tags.Contains(x.Id)).ToList();
public class Driver
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string NationalCode { get; set; }
public string CellPhone { get; set; }
public string LicenseNumber { get; set; }
public bool IsDriverAssistance { get; set; }
[InverseProperty("Driver")]
public virtual ICollection<Transference> Transferences { get; set; }
[InverseProperty("DriverAssistance")]
public virtual ICollection<Transference> TransferencesForAssistance { get; set; }
[InverseProperty("Driver")]
public virtual ICollection<Tanker> Tankers { get; set; }
[InverseProperty("DriverAssistance")]
public virtual ICollection<Tanker> TankersForAssistance { get; set; }
}
public class Transference
{
public string Id { get; set; }
public DateTime Date { get; set; }
public Int16 Lytrazh { get; set; }
public bool IsEMS { get; set; }
public DateTime LoadingDate { get; set; }
public DateTime DeliveryDate { get; set; }
[InverseProperty("Transferences")]
public virtual Driver Driver { get; set; }
[InverseProperty("TransferencesForAssistance")]
public virtual Driver DriverAssistance { get; set; }
public virtual TypeOfTanker TypesOfTanker { get; set; }
public virtual Tanker Tanker { get; set; }
public virtual Consumer Consumer { get; set; }
}
public class TransferenceConfig : EntityTypeConfiguration<Transference>
{
public TransferenceConfig()
{
// one-to-many
this.HasRequired(x => x.Consumer)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.TypesOfTanker)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.Tanker)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.Driver)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.DriverAssistance)
.WithMany(x => x.Transferences);
}
}
public class TransferenceConfig : EntityTypeConfiguration<Transference>
{
public TransferenceConfig()
{
// one-to-many
this.HasRequired(x => x.Consumer)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.TypesOfTanker)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.Tanker)
.WithMany(x => x.Transferences);
// one-to-many
this.HasRequired(x => x.Driver)
.WithMany(x => x.Transferences);
//--------------------------------------------------------------------------------------
// one-to-many
this.HasRequired(x => x.DriverAssistance)
.WithMany(x => x.TransferencesForAssistance);
//---------------------------------------------------------------------------------------
}
}
namespace EF_Sample35.DataLayer
{
public class Sample35Context : DbContext
{
public DbSet<AlimentaryHabits> AlimentaryHabits { set; get; }
public DbSet<Customer> Customers { set; get; }
...
...
}
}
سلام
من هم با نظر شما در مورد بروز رسانی کلید اصلی موافقم.
اما واقعیت متفاوت تره.
من تو یه نرم افزار شماره پرسنلی که نوعش هم عدد صحیح بود کردم کلید اصلی.
بعد از 6 ماه متوجه شدن که شماره پرسنلی یکی از کارمندان رو اشتباه وارد کردن!
البته من از ef database first استفاده میکردم که اونجا هم مثل بقیه ormها اجازه update کردن کلید اصلی رو نمیده.
سعید جان میدونم که اینکار میشه- مطمئنا شماره ملیشون رو uniqe کردم!
ما برای انتخاب کلید اصلی دو حالت داریم -
1- استفاده از کلیدهای طبیعی مثل شماره پرسنلی
2- استفاده از کلیدهای جانشین مثل یک فیلد identity - این حالت موقعی استفاده میشه که کلید طبیعی نداشته باشیم
تکرار داده در جداول مختلفی که به آن ارتباط پیدا میکنند ??
تکرار چه داده ای؟
سعید جان مطمئنا کلید شما تو جداول برای رابطه استفاده میشه حالا چه طبیعی باشه چه جانشین.
با فرض اینکه با 10 جدول ارتباط داشته باشه با n تعداد رکورد . حالا 6 ماهی یک بار این اتفاق چه ایرادی داره؟
بگذریم . موفق باشید
- تکرار دادهای که قرار هست ویرایش بشه. فرض کن که یک لینک از کارمند مورد نظر ایجاد شده با شماره پرسنلی که pk است. الان این لینک یاد داشت شده دیگه کار نمیکنه. این یک مثال ساده است. یا به روز رسانی تمام رکوردهای یک جدول با یک update که تریگر هم روش تعریف شده ممکنه مشکل ساز بشه یا اصلا کار نکنه.
- در ef هر موجودیت نیاز به یک کلید منحصربفرد داره برای شناسایی و از این کلید در سیستم ردیابی خودش استفاده میکنه. اگر این کلید قرار باشه تغییر کنه، ef نیاز داره تا یک وهله جدید رو خلق کنه و نمونه قبلی رو نابود. به این ترتیب عملکردش بهم میخوره و مجبور میشه رکورد جدید ثبت کنه بجای آپدیت قبلی. البته این کارها هم بدعتی نیست چون طراحی اون برای اساس اصول domain driven design انجام شده.
modelBuilder.Entity<Department>()
.HasOptional(x => x.Administrator);public int? InstructorID { get; set; } public class Order
{
public int OrderId { get; set; }
public virtual Quotation Quotation { get; set; }
}
public class Quotation
{
public int QuotationId { get; set; }
public virtual Order Order { get; set; }
} public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
this.HasOptional(x => x.Quotation)
.WithOptionalPrincipal()
.Map(x => x.MapKey("OrderId"));
}
}
public class QuotationMap : EntityTypeConfiguration<Quotation>
{
public QuotationMap()
{
this.HasOptional(x => x.Order)
.WithOptionalPrincipal()
.Map(x => x.MapKey("QuotationId"));
}
}public CustomerConfig()
{
// many-to-many
this.HasMany(p => p.Roles)
.WithMany(t => t.Customers)
.Map(mc =>
{
mc.ToTable("RolesJoinCustomers");
mc.MapLeftKey("RoleId");
mc.MapRightKey("CustomerId");
});
}
}HasOptional ( c => c.Project ).WithMany (c => c.ProjectRowCollection).HasForeignKey(c => c.ProjectID).WillCascadeOnDelete();
ProjectRowCollection.Remove(ProjectRowItem);
If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.
Project.ProjectRowCollection.Remove(ProjectRowItem);
// یک سایت که چندین بلاگ دارد
public class Site
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Blog> Blogs { set; get; }
}
public class Blog
{
public int Id { get; set; }
public string Name { set; get; }
[ForeignKey("SiteId")]
public virtual Site Site { get; set; }
public int SiteId { set; get; }
} HasMany(x => x.Ads).WithRequired(x => x.User).WillCascadeOnDelete();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<ImageGallery>().HasOptional(T => T.Pic).WithOptionalPrincipal().WillCascadeOnDelete(true);
db.ImageGalleries.Remove(db.ImageGalleries.Find(imageGallery_ID)); db.SaveChanges();
pulbic class User
{
public int Id { get; set; }
public string FullName { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Text { get; set; }
public int UserId { get; set; }
public int? UserId2 { get; set; }
[ForeignKey(nameof(UserId))
public virtual User User { get; set; }
[ForeignKey(nameof(UserId2))
public virtual User User2 { get; set; }
} public class User
{
public int UserId { get; set;}
public string Name { get; set; }
public virtual ICollection<Comment> HomeCommentes { get; set; }
public virtual ICollection<Comment> AwayCommentes { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
public int HomeUserId { get; set; }
public int GuestUserId { get; set; }
public virtual User HomeUser { get; set; }
public virtual User GuestUser { get; set; }
}
public class Context : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Comment>()
.HasRequired(m => m.HomeUser)
.WithMany(t => t.HomeCommentes)
.HasForeignKey(m => m.HomeUserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Comment>()
.HasRequired(m => m.GuestUser)
.WithMany(t => t.AwayCommentes)
.HasForeignKey(m => m.GuestUserId)
.WillCascadeOnDelete(false);
}
}