這是一個簡短問題的長篇介紹,對不起!實體框架4.3.1代碼優先導航屬性映射和可見性
我與EF 4.3.1代碼優先工作,我有以下的模型
public class Action
{
protected Action()
{ }
public virtual int ActionID { get; protected set; }
[Required]
[StringLength(DataValidationConstants.NameLength)]
public virtual string Name {get; set;}
[StringLength(DataValidationConstants.DescriptionLength)]
public virtual string Description { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual void AuthorizeRole(Role role)
{
if (IsRoleAuthorized(role))
throw new ArgumentException("This role is already authorized", "role");
Roles.Add(role);
}
}
public class Role
{
protected Role()
{ }
public virtual int RoleID { get; protected set; }
[Required]
[StringLength(DataValidationConstants.NameLength)]
public virtual string Name { get; set; }
[StringLength(DataValidationConstants.DescriptionLength)]
public virtual string Description { get; set; }
}
而且我的DbContext類,在其他一些類庫定義,多對多映射:
public class myDB : DbContext
{
public DbSet<Domain.Action> Actions { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Domain.Action>()
.HasMany(action => action.Roles)
.WithMany()
.Map(map => map.ToTable("AuthorizedRoles"));
}
}
所以,這工作正常。但是如果注意到方法Action.AuthorizeRole(Role role)
很容易假設角色授權邏輯可能很複雜(現在某些已經授權的驗證,但可以是任何驗證,對嗎?),這對於一個很好的老式方法是完全有效的領域模型。但是......根據Requirements for Creating POCO Proxies,角色系列public virtual ICollection<Role> Roles {get; set;}
需要公開,至少是獲得者。這意味着任何Action類的客戶端都可以添加或刪除角色,繞過任何驗證邏輯。 是的,我想延遲加載,更改跟蹤,作品,所以我確實需要創建代理。
Regardlles,我開始測試一些方法,我可以使這個屬性public virtual ICollection<Role> Roles {get; set;}
非公有財產,以便以後測試代理創建。由於代理生成了我自己的類的子類,並且因爲我信任我的繼承者而不是我的客戶,所以我決定使這樣的屬性成爲protected virtual ICollection<Role> Roles {get; set;}
。不過,當然,我得到一個編譯錯誤就行了
modelBuilder.Entity<Domain.Action>()
.HasMany(action => action.Roles)
.WithMany()
.Map(map => map.ToTable("AuthorizedRoles"));
因爲現在的財產受到保護,不能被Action類或其繼承人以外的訪問,當然myDB
上下文類是完全一致的。
因此,我需要嘗試訪問從myDB
類沒有它(財產)被公開的財產。而我雖然是反思。我的上下文類看起來是這樣,那麼:
public class myDB : DbContext
{
public DbSet<Domain.Action> Actions { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Domain.Action>()
.HasMany(action => ExtractPropertyValue<ICollection<Role>>(action, "Roles"))
.WithMany()
.Map(map => map.ToTable("AuthorizedRoles"));
}
protected virtual TProperty ExtractPropertyValue<TProperty>(object instance, string propertyName)
{
if(instance == null)
throw new ArgumentNullException("instance", "Can't be null");
if (string.IsNullOrWhiteSpace(propertyName))
throw new ArgumentException("Can't be null or white spaced", "propertyName");
Type instanceType = instance.GetType();
PropertyInfo propertyInfo = instanceType.GetProperty(propertyName, BindingFlags.NonPublic);
return (TProperty)propertyInfo.GetValue(instance, null);
}
}
公告實施新方法ExtractPropertyValue
,螞蟻的許多調用它的許多映射指令。這可行嗎? HasMany方法需要一個接收一個Action並返回一個ICollection(在這種情況下爲Role)的函數,這就是所得到的結果。但是,不,它不工作,它編譯courrse,但在運行時,我得到了異常,就像「這個expresion必須是一個有效的屬性,如obj => obj.MyProperty」。
所以好吧,它需要是一個「直接」屬性,它需要訪問de DBContext類。我決定將我的屬性設置爲受保護的內部,並將我的DBContext類移動到我的Domain類庫(其中定義了所有實體),但我真的不那麼喜歡它,但是我更喜歡讓所有人都可以訪問我的屬性。我的屬性是這樣的:
protected internal virtual ICollection<Role> Roles { get; set; }
而且我的DbContext類這樣的,完全按照我先過它,只知道它現在是在同一個類庫定義爲所有的實體是:
public class mrMantisDB : DbContext
{
public DbSet<Domain.Action> Actions { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Domain.Action>()
.HasMany(action => action.Roles)
.WithMany()
.Map(map => map.ToTable("AuthorizedRoles"));
}
}
這工作正常。 因此,現在唯一需要檢查的是代理的創建,即延遲加載和更改跟蹤。作爲財產保護內部而不是公開的,我擔心它可能無法正常工作,但是它確實如此,而且確實如此。
現在,這裏是我的問題/請求。如果一個導航屬性並不需要被公開來創建代理,那麼protected就足夠了(我將內部出去,因爲我認爲它隻影響將該屬性用於關係映射的能力),爲什麼地球上的限制在表達式中爲HasMany方法提取屬性,或者更好,因爲我知道該屬性必須是被映射類型的屬性,而不是一些隨機集合,爲什麼HasMany中沒有重載,它需要一個字符串propertyName和即使它不是公共財產,也會搜索該財產。這將允許具有非公共導航屬性,這在我看來,一路走來讓一個整潔的設計對象domian。
也許我在這裏錯過了一些東西。
非常感謝。
我嘗試過類似的方法與implementantion方法ExtractPropertyValue(你可以在我原來的問題上看到代碼)用於映射關係的一端與HasMany並得到以下異常味精**表達式應該代表一個屬性:C#:'t => t.MyProperty'VB。淨:'函數(t)t.MyProperty'。**我也試過實施一種方法P ropertyValueExtractor返回一個表達式來獲取屬性值而不是屬性值本身,並得到完全相同的異常消息。雖然謝謝!我正在使用EF 4.3.1 – 2012-08-06 15:25:47