2014-04-20 157 views
2

我想解決一個基本問題,並且我有點卡住了。C#繼承挑戰

我有一個基類:

public abstract class EntityBase<TEntity> where TEntity : class 
{ 
    public virtual int Id { get; set; } 
    public virtual DateTime DateCreated { get; set; } 
    public virtual DateTime DateModified { get; set; } 
} 

這被保存到數據庫中的所有類(使用EF)繼承。

然後我有一個複雜類型:

public class Address 
{ 
    public virtual string ContactName { get; set; } 
    public virtual string Line1 { get; set; } 
    public virtual string Line2 { get; set; } 
    public virtual string Line3 { get; set; } 
    public virtual string City { get; set; } 
    public virtual string State { get; set; } 
    public virtual string PostalCode { get; set; } 
    public virtual string Country { get; set; } 
} 

而一個CustomerAddress這是相同的字段Address類型,但需要持久化到數據庫。

public class CustomerAddress : EntityBase<CustomerAddress> 
{ 
    public virtual int CustomerId { get; set; } 

    public virtual string ContactName { get; set; } 
    public virtual string Line1 { get; set; } 
    public virtual string Line2 { get; set; } 
    public virtual string Line3 { get; set; } 
    public virtual string City { get; set; } 
    public virtual string State { get; set; } 
    public virtual string PostalCode { get; set; } 
    public virtual string Country { get; set; } 
} 

我知道你只能在C#中的時間繼承一個類,但我怎樣才能使這項工作,這樣基本上CustomerAddress繼承這兩個類的?

任何想法?

+0

1)爲什麼'EntityBase'的泛型參數? 2)接口支持多重繼承3)您是否考慮過在這裏使用組合而不是繼承? – CodesInChaos

+0

@CodesInChaos - 所以我可以使用該類型作爲約束來確保它是一個類。 – Sam

+0

@CodesInChaos - '您是否考慮過在這裏使用組合而不是繼承?'您能否在這段代碼的上下文中提供一個快速示例? – Sam

回答

3

如果您使用Address作爲實體類CustomerAddress的參數,該怎麼辦?

public class CustomerAddress : EntityBase<CustomerAddress> 
{ 
    public int CustomerId { get; set; } 

    [ForeignKey("CustomerId")] 
    public virtual Customer Customer { get; set; } 

    public Address BaseAddress { get; set; } 
} 
0

所以我結束了在這裏做了選擇compositioninheritance

地址接口

public interface IAddress 
{ 
    string ContactName { get; set; } 
    string Line1 { get; set; } 
    string Line2 { get; set; } 
    string Line3 { get; set; } 
    string City { get; set; } 
    string State { get; set; } 
    string PostalCode { get; set; } 
    string Country { get; set; } 
} 

地址複雜類型

public class Address : IAddress 
{ 
    public virtual string ContactName { get; set; } 
    public virtual string Line1 { get; set; } 
    public virtual string Line2 { get; set; } 
    public virtual string Line3 { get; set; } 
    public virtual string City { get; set; } 
    public virtual string State { get; set; } 
    public virtual string PostalCode { get; set; } 
    public virtual string Country { get; set; } 
} 

CustomerAddress類型

public class CustomerAddress : EntityBase<CustomerAddress>, IAddress 
{ 
    public virtual int CustomerId { get; set; } 
    public virtual AddressType AddressType { get; set; } 
    public virtual bool IsDefault { get; set; } 
    public virtual string Nickname { get; set; } 

    public virtual string ContactName { get; set; } 
    public virtual string Line1 { get; set; } 
    public virtual string Line2 { get; set; } 
    public virtual string Line3 { get; set; } 
    public virtual string City { get; set; } 
    public virtual string State { get; set; } 
    public virtual string PostalCode { get; set; } 
    public virtual string Country { get; set; } 
} 

我認爲它解決了這個問題,並清楚地說明了這些意圖。

有沒有異議?

1

也許我提出以下建議,這是我用我自己的EF支持的項目:

我有一個Address類從另一個類繼承Int32EntityInt32Entity繼承於另一個類Entity並實現兩個接口:ICreatableEntity_TKey;和IIndexableEntity_TKey。最後,Entity類還實現了兩個其他接口:ICreatableEntity;和IRemovableEntity。所以,令人困惑的是,這裏是在正確的順序代碼:

ICreatableEntityICreatableEntity_TKey接口

public interface ICreatableEntity { 
    Employee CreatedBy { get; set; } 
    DateTime CreatedDateTime { get; set; } 
} 

public interface ICreatableEntity<TKey> : 
    ICreatableEntity { 
    TKey CreatedById { get; set; } 
} 

IIndexableEntity_TKey接口

public interface IIndexableEntity<TKey> 
    where TKey : struct { 
    TKey Id { get; set; } 
} 

IRemovableEntity接口

public interface IRemovableEntity { 
    bool IsRemoved { get; set; } 
    int? RemovedById { get; set; } 
    DateTime? RemovedDateTime { get; set; } 

    Employee RemovedBy { get; set; } 
} 

實體

public class Entity : 
    ICreatableEntity, 
    IRemovableEntity { 
    #region ICreatableEntity Members 
    public DateTime CreatedDateTime { get; set; } 

    public virtual Employee CreatedBy { get; set; } 
    #endregion 

    #region IRemovableEntity Members 
    public bool IsRemoved { get; set; } 
    public int? RemovedById { get; set; } 
    public DateTime? RemovedDateTime { get; set; } 

    public virtual Employee RemovedBy { get; set; } 
    #endregion 

    public Entity() { 
     this.CreatedDateTime = DateTime.Now; 
    } 
} 

Int32Entity

public class Int32Entity : 
    Entity, 
    ICreatableEntity<int>, 
    IIndexableEntity<int> { 
    #region ICreatableEntity`TKey Members 
    public int CreatedById { get; set; } 
    #endregion 

    #region IIndexableEntity Members 
    public int Id { get; set; } 
    #endregion 
} 

最後,但並非最不重要的地址類(省略了一些項目特定的代碼)

public class Address : Int32Entity { 
    public string Street { get; set; } 
    public string City { get; set; } 
    public int Zip { get; set; } 
    public string Building { get; set; } 
    public string Unit { get; set; } 
    public UnitType? UnitType { get; set; } 
    public string CrossStreets { get; set; } 
    public int? GateCode { get; set; } 
    public AddressType Type { get; set; } 
    public DbGeography Position { get; set; } 

    #region Relationship Properties 
    public byte StateId { get; set; } 

    public virtual State State { get; set; } 
    #endregion 
} 

還有byteshort及其可空的等價物Int32Entity類。雖然它看起來可能有很多的繼承,但它起作用,而且效果很好。這些接口基本上保證了繼承對象將具有描述何時被創建或刪除以及由誰來描述的屬性。多個被竊等級也是將事情分開的必要條件,因爲我確實有一些不像其他實體那樣行爲的實體,比如那些具有複合關鍵字的實體。

此外,接口然後可以在您的項目層次結構用作泛型約束別的地方如果需要的話,我在我的DbContext實施做了這裏Entity Framework 6.1 - SaveChanges fails with Optional Principal relationship(答案)。

最後,一對夫婦的批評筆記:

  • 你使用太多字符串爲您的屬性。 StateCountry屬性應分解爲單個的StateCountry對象,然後將其與您的Address對象關聯。請參閱下面的示例。
  • Line1,Line2Line3屬性對於除您之外的任何人都絕對沒有任何意義。雖然它通常用於整個Interworld的形式,但我個人認爲它很sl。。請注意,在我的Address課程中,我試圖獲得非常詳細的內容,所以我知道什麼是什麼,然後我可以轉向並格式化數據以便按需顯示。
  • 沒有必要爲一個對象創建一個IAddress接口。接口是爲了在多個對象中使用,而你並沒有這樣做。如果你繼續沿着這條道路前進,那麼最終可能會有Email : IEmail,Phone : IPhone等等,這些都是毫無意義的。
  • 您正在使用virtual關鍵字太多。 virtual用於延遲加載相關的實體,而不是對象的屬性。您永遠不會延遲加載CityState,PostalCodeCountry屬性,這些屬性在地址上彼此獨立,因爲那樣它就不再是一個完整且有用的地址。

忽略這一行,試圖欺騙,使文本格式...

public class State { 
    // If you need more than 256 State entities, just bump it to a short 
    // and you should be good to for every possible State (or Province) in the world 
    public byte Id { get; set; } 
    public string Abbreviation { get; set; } 
    public string Name { get; set; } 
} 

public class Country { 
    public byte Id { get; set; } 
    public string Abberviation { get; set; } 
    public string Name { get; set; } 
} 

public class Address { 
    // Blah, blah, blah... 

    // Nullable because not all countries have states 
    public byte? StateId { get; set; } 
    public byte CountryId { get; set; } 

    public virtual State { get; set; } 
    public virtual Country { get; set; } 
} 

我希望這可以幫助你。