0

這是一個簡短問題的長篇介紹,對不起!實體框架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。

也許我在這裏錯過了一些東西。

非常感謝。

回答

1

您的問題被問到爲什麼對模型構建器的保護屬性的限制,我不知道爲什麼這樣。不過,如果您需要解決方法,我已成功實施this blog的解決方案。

您將更新與表達你的實體,以便在模型構建器中可以找到它:

protected virtual ICollection<Role> Roles { get; set; } 

     public class PropertyAccessExpressions 
     { 
      public static readonly Expression<Func<User, ICollection<Role>>> ID = x => x.Roles; 
     } 

那麼你的建設者應該能夠找到這樣的:

modelBuilder.Entity<Domain.Action>() 
      .HasMany(action => action.Roles) 
+0

我嘗試過類似的方法與implementantion方法ExtractPropertyValue(你可以在我原來的問題上看到代碼)用於映射關係的一端與HasMany並得到以下異常味精**表達式應該代表一個屬性:C#:'t => t.MyProperty'VB。淨:'函數(t)t.MyProperty'。**我也試過實施一種方法P ropertyValueExtractor返回一個表達式來獲取屬性值而不是屬性值本身,並得到完全相同的異常消息。雖然謝謝!我正在使用EF 4.3.1 – 2012-08-06 15:25:47

相關問題