0

物理モデルに1:1で対応するドメインモデルがあるとします。また:

  • 物理モデルのすべてのテーブルには、主キーとして列名「Id」があります
  • 多くのテーブルには「LastChanged」タイムスタンプ列があります
  • 一部のテーブルにはローカライズされたデータが含まれています

目的:ドメインモデルクラス(POCO)と適切なリポジトリを作成します。ツール-VS2010、EF4.1

最も明白なアプローチは、DBからEFモデルを生成し、その上でT4POCOGeneratorを実行することです。出力はPOCOクラスのセットです。

//POCO classes
public class Country
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime LastModified { get; set; }
    ...
}

public class User
{
    public int Id { get; set; }
    public string FirtsName { get; set; }
    public DateTime LastModified { get; set; }
    ...
}

これまでのところ良いですが、リポジトリを実装するときにいくつかのコードの重複に遭遇します。インターフェイス定義レベルの両方:

public interface ICountryRepository
{
    IEnumerable<Country> FindAll();

    Country FindById(int id);

    void Add(Country country);

    void Delete(Country country);
}

//Here the ONLY difference is the type of the entity
public interface IUserRepository
{
    IEnumerable<User> FindAll();

    User FindById(int id);

    void Add(User user);

    void Delete(User user);
}

そして、実装レベルでは:

class CountryRepository : ICountryRepository
{
    IEnumerable<Country> FindAll()
    {
        //implementation
    }

    Country FindById(int id)
    {
        //find by id logic
    }

    void Add(Country country)
    {
        //logic
    }

    void Delete(Country country)
    {   
        //logic
    }
}

class UserRepository : IUserRepository
{
    IEnumerable<User> FindAll()
    {
        //the only difference in the implementation
        //is the type of returned entity
    }

    User FindById(int id)
    {
        //the only difference in the implementation
        //is the type of returned entity
    }

    void Add(User user)
    {
        //the only difference in the implementation
        //is the type of returned entity
    }

    void Delete(User user)
    {
        //the only difference in the implementation
        //is the type of returned entity
    }
}

上記のコードのほとんどはより一般的に記述できることを考慮に入れると、次のアプローチを取ることもできます。

POCOオブジェクト階層を作成します。

public class  EntityBase
{
    public int Id { get; set; }
}

public class TrackableEntity : EntityBase
{
    public DateTime LastChanged { get; set; }
}

public class LocalizedEntity : TrackableEntity
{
    public int ResourceId { get; set; }
}

public class Country : LocalizedEntity
{
}

そして、基本実装のリポジトリ階層:

public interface IRepository<TEntity> where TEntity : EntityBase
{
    IEnumerable<TEntity> FindAll();

    TEntity FindById(int id);

    void Add(TEntity entity);

    void Delete(TEntity entity);
}

public interface ILocalizedRepository<TEntity> : IRepository<TEntity> where TEntity : LocalizedEntity
{
    IEnumerable<TEntity> FindByCultureIso2(string cultureIso2);
}

public interface ICountryRepository : ILocalizedRepository<Country>
{
}

internal class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : EntityBase
{
    private readonly IObjectSet<TEntity> _objectSet;

    public RepositoryBase(ObjectContext database)
    {
        _objectSet = database.CreateObjectSet<TEntity>();
    }

    protected virtual IQueryable<TEntity> All()
    {
        return _objectSet;
    }

    public virtual IEnumerable<TEntity> FindAll()
    {
        return All().ToList();
    }

    public virtual TEntity FindById(int id)
    {
        return All().Where(entity => entity.Id == id).SingleOrDefault();
    }

    public virtual void Add(TEntity entity)
    {
        _objectSet.AddObject(entity);
    }

    public virtual void Delete(TEntity entity)
    {
        _objectSet.DeleteObject(entity);
    }
}

internal class LocalizedRepositoryBase<TEntity> : RepositoryBase<TEntity>, ILocalizedRepository<TEntity> where TEntity : LocalizedEntity
{
    public LocalizedRepositoryBase(ObjectContext database) : base(database)
    {
    }

    protected override IQueryable<TEntity> All()
    {
        return (base.All() as ObjectSet<TEntity>).Include("Resource.LocalizedResources.Culture");
    }

    public IEnumerable<TEntity> FindByCultureIso2(string cultureIso2)
    {
        IEnumerable<TEntity> entities = All().Where(...);

        return entities.ToList();
    }
}

internal class CountryRepository : LocalizedRepositoryBase<Country>, ICountryRepository
{
    public CountryRepository(ObjectContext database) : base(database)
    {
    }
}

後者のアプローチの魅力的な利点は、コードがはるかに構造化されているため、コードの重複を回避できることです。

しかし、このシナリオは、大量の手作業の表面を開くT4コード生成にはほとんど適していません。

次のことを考えていることを教えていただければ幸いです。

  • コードの美しさは、手動で実装する手間をかけるだけの価値があると思いますか?
  • コードの重複を取り除く他の方法はありますか?
4

2 に答える 2

2

最大の懸念事項がPOCOの手動実装である場合は、基本クラスの代わりにインターフェイスを使用して共有機能を定義します。

public interface IEntityBase
{
    int Id { get; set; }
}

public interface ITrackableEntity : IEntityBase
{
    DateTime LastChanged { get; set; }
}

public interface ILocalizedEntity : ITrackableEntity
{
    int ResourceId { get; set; }
}

これで、POCOを手動で実装する必要はありません。Generatorはエンティティを作成し、実装するインターフェイスを定義するには、エンティティごとに部分的な部分を定義するだけで済みます。

public partial class Country : ILocalizedEntity
{ } 

T4の変更に満足している場合は、インターフェイス解像度をT4に直接追加することもでき、それらの部分的な部分を定義する必要はありません。

于 2011-11-21T11:11:02.103 に答える
0

コードを生成している場合は、複製しても問題ありません。生成されたコードに触れないでください。問題はありません。

于 2011-11-21T09:52:53.503 に答える