2011-08-25 42 views
9

使用實體框架代碼 - 首先我必須公開所有屬性來生成數據庫,這意味着使用實體框架代碼優先的方法我不得不將anemic domain與一個豐富的模型混合?因爲不需要公開的屬性必須是。使用實體框架代碼 - 首先,我需要讓我的域的模型貧血?

例如:

使用型號豐富,這在實體框架將不起作用:

public class Car 
{ 
    private int _actualPosition; 

    public void Accelerate() 
    { 
     this._actualPosition += 10; 
    } 
} 

要工作,我們需要做_actualPosition市民:

public class Car 
{ 
    public int ActualPosition { get; set; } 

    public void Accelerate() 
    { 
     this.ActualPosition += 10; 
    } 
} 

現在實體國際海事組織是醜陋的,因爲我有一個方法,增加+10的財產,並在同一時間公開,我不想那個公關操作公開。

又如:

想象我想要一個關係多到很多,但與 只有一個辦法,如:

public class User 
{ 
    public long Id { get; set; } 

    public string Name { get; set; } 

    public IList<Role> Roles { get; set; } 
} 

public class Role 
{ 
    public long Id { get; set; } 

    public string Name { get; set; } 
} 

我如何做一個多一對多的關係用那個模型?據我所知,沒有辦法,我必須做一個雙向關係:

public class User 
{ 
    public long Id { get; set; } 

    public string Name { get; set; } 

    public IList<Role> Roles { get; set; } 
} 

public class Role 
{ 
    public long Id { get; set; } 

    public string Name { get; set; } 

    public IList<User> Users { get; set; } 
} 

有了這個模式,我就可以做出許多一對多的關係:

modelBuilder.Entity<User>() 
       .HasMany(x => x.Roles) 
       .WithMany(y => y.Users); 

我對不對?如果是的話,實體框架是不討人喜歡的。

「又如」@Slauma的回答工作:

modelBuilder.Entity<User>() 
      .HasMany(x => x.Roles) 
      .WithMany() 
      .Map(a => 
      { 
       a.MapLeftKey("UserId"); 
       a.MapRightKey("RoleId"); 
       a.ToTable("UserRoles"); 
      }); 
+0

你肯定不需要性質EF EDMX公開,所以我如果您首先爲EF代碼做過,會感到驚訝。是否真的沒有註釋或可用於指定所需屬性的東西?不過,我認爲你絕對需要訪問者。受保護或內部訪問者會工作嗎? (我原本以爲私人,但我懷疑至少需要保護它。) – Rup

+2

@Rup:沒有沒有註釋。屬性不必是公共的,但它們必須對EF上下文和映射可見。 –

+0

@Ladislav在這種情況下,你是否同意EF? –

回答

1

答案很簡單:除非框架支持它,你被卡住想太多擠進這個類如果您嘗試同時使用業務規則和公共屬性。

龍答: 我曾經使用的系統非常喜歡這一點,基本上我來到認識到測試和封裝的最好辦法是來包裝這個類我真正的域類。

public class Car 
{ 
    private CarPersistence _carPersistence; 

    public void Accelerate() 
    { 
     this._carPersistence.ActualPosition += 10; 
    } 

    public Car (CarPersistence car) { 
     _carPersistence = car; 
    } 
} 

public class CarPersistence 
{ 
    public int ActualPosition; 
} 

當我這樣做過,我能夠再有我的下級Persistence類實現,可以通過我的測試中被用來注入用於簡單的測試業務類的接口,而不必跟數據庫。

一個這樣的系統,你的業務類在一個「層」上,而你的持久化類在另一個「層」上,你可以很容易地建立一對多的關係,只需要構建到你的業務構建中班列持久類:

public class User 
{ 
    private UserPersistence _user; 
    private IList<Persistence> _roles; 

    public User (UserPersistence user, IList<Persistence> roles) { 
     _user = user; 
     _roles = roles; 
    } 
} 

對不起,語法可能不是完美的,這是我能記得它從VB音譯爲C#最好的;)

1

你可以設置你的Car實體是這樣的:

public class Car 
{ 
    public int ActualPosition { get; private set; } 

    public void Accelerate() 
    { 
     this.ActualPosition += 10; 
    } 
} 

這會強制修改ActualPosition屬性以使用專門的Accelerate方法。使用這種風格的副作用是您的Accelerate方法不可測試。

您還可以設置它是這樣的:

public class Car 
{ 
    protected int ActualPosition { get; set; } 

    public void Accelerate() 
    { 
     this.ActualPosition += 10; 
    } 
} 

但是這種方法也不是沒有使用反射直接測試。

0

是的,您發佈的代碼是Anemic Model。此外,我甚至不會將其稱爲適當的面向對象代碼。沒有簡單的封裝,對象只是一個數據容器。看起來您選擇的ORM正在限制您的域實施選擇。對於它的價值,NHibernate允許你直接映射字段(即使這些字段是隻讀的)。它不需要對象具有屬性。例如:

public class Car { 

    private int _position; 

    public void Accelerate() { 
     _position += 10; 
    } 
} 

可以映射爲:

<class name="Car" table="Cars" > 
    ... 
    <property name="_position" column="Position" /> 
    ... 
</class> 
+0

是的,我知道NH允許這樣做,所以我很驚訝爲什麼實體框架沒有提出相同的要求。 –

3

你 「又如」 是不正確的。你不是被迫在模型類中暴露關係的兩端作爲屬性。在您的例子,你可以從你的Role類中刪除public IList<User> Users { get; set; }和定義映射像這樣:

modelBuilder.Entity<User>() 
      .HasMany(x => x.Roles) 
      .WithMany() 
      .Map(a => 
      { 
       a.MapLeftKey("UserId"); 
       a.MapRightKey("RoleId"); 
       a.ToTable("UserRoles"); 
      }); 

這也是案件的一個一對多的關係。總是存在無參數With...過載,WithMany(),WithRequired(),WithOptional()等,以定義兩端不在模型中暴露的關係的映射。

+0

但是,如果我從實體框架生成數據庫?你確定我不需要公開兩個屬性? –

+0

你是對的,我做測試。謝謝,我會更新這個問題。 –

+0

@Acaz:當您從數據庫創建模型時,EF可能會默認創建兩個集合。但是,您可以從生成的模型類中刪除關係的一側。 – Slauma

1

我相信你正在尋找的是以下幾點:

public class Car 
{ 
    public int Id { get; set; } 
    public int ActualPosition { get; private set; } 

    public void Accelerate() 
    { 
     this.ActualPosition += 10; 
    } 
} 

單元測試是下面:

[TestMethod] 
    public void AccellerateWillAddTenUnitsToTheActualPosition() 
    { 
     //Arrange 
     var car = new Car(); 
     var actualPosition = car.ActualPosition; 
     var expectedPosition = actualPosition + 10; 

     //Act 
     car.Accelerate(); 

     //Assert 
     Assert.AreEqual(car.ActualPosition, expectedPosition); 
    }