0

IDataRecord を返すデータ アクセス レイヤーがあります。DataContracts (dto's) を提供する WCF サービスがあります。これらの DataContracts は、次のように IDataRecord を含むパラメーター化されたコンストラクターによって開始されます。

[DataContract]
public class DataContractItem
{
    [DataMember]
    public int ID;
    [DataMember]
    public string Title;

    public DataContractItem(IDataRecord record)
    {
        this.ID = Convert.ToInt32(record["ID"]);
        this.Title = record["title"].ToString();
    }
}

残念ながら、DAL を変更することはできないため、IDataRecord を入力として使用する必要があります。しかし、一般的に、これは非常にうまく機能します。ほとんどの場合、マッピングは非常に単純ですが、もう少し複雑な場合もありますが、ロケット科学ではありません。

ただし、ジェネリックを使用してさまざまな DataContracts をインスタンス化し、WCF サービス メソッドを簡素化できるようにしたいと考えています。私は次のようなことができるようにしたい:

public T DoSomething<T>(IDataRecord record) {
    ...
return new T(record);
}

だから私は次の解決策を試みました:

  1. コンストラクターでジェネリック型付きインターフェイスを使用します。機能しません: もちろん、インターフェースでコンストラクターを定義することはできません

  2. 静的メソッドを使用して DataContract をインスタンス化し、この静的メソッドを含む型付きインターフェイスを作成します。機能しません: もちろん、インターフェイスで静的メソッドを定義することはできません

  3. new() 制約を含む汎用の型付きインターフェイスを使用しても機能しません: new() 制約にパラメーター (IDataRecord) を含めることはできません

  4. ファクトリ オブジェクトを使用して、DataContract タイプに基づいてマッピングを実行します。動作しますが、1 つのファイルにすべてのマッピングを含む switch ステートメントがあるため、あまりクリーンではありません。

これに対する真のクリーンな解決策が見つかりません。誰かが私のためにこれに光を当てることができますか? プロジェクトは、複雑なマッピング手法には小さすぎ、「スイッチベース」のファクトリ実装には大きすぎます。

4

3 に答える 3

2

これには AutoMapper を使用できると思います。これはオープン ソース プロジェクトであり、やりたいことができるようになります。あなたの何かであなたはこれをするでしょう:

public TDestination DoSomething<TDestination>(IDataRecord record) {
   return Mapper.Map(reader, reader.GetType(), typeof(TDestination));
}

それを行う前に、マップを設定します

Mapper.CreateMap<IDataRecord, MyDestinationType>()
于 2010-05-27T13:12:45.957 に答える
2

リフレクションを通じて型コンストラクターを呼び出すことができます。

public T DoSomething<T>(IDataRecord record)
{
    //do something...

    var ci = typeof(T).GetConstructor(new[] { typeof(IDataRecord) });
    return (T)ci.Invoke(new object[] { record });
}

編集:上記のアプローチは非常に脆弱であり、慣習に依存しているため、別のアプローチは、初期化を許可するデータ コントラクト用のインターフェイスを作成することです。

public interface IDataContract
{
    void Initialise(IDataRecord record);
}

public T DoSomething<T>(IDataRecord record) where T : IDataContract, new()
{
    //do something

    T contract = new T();
    contract.Initialise(record);

    return contract;
}
于 2010-05-27T12:55:37.393 に答える
1

これが私がそれを行う方法です..

ビジネス オブジェクトを DataRow に、またはその逆に変換できるDataRow の拡張メソッド。

/// <summary>
/// Extension methods for DataRow.
/// </summary>
public static class DataRowExtensions
{
    /// <summary>
    /// Converts DataRow into business object.
    /// </summary>
    /// <typeparam name="TEntity">A type that inherits EntityBase.</typeparam>
    /// <param name="dataRow">DataRow object to convert to business object.</param>
    /// <returns>business object created from DataRow.</returns>
    public static TEntity ToEntity<TEntity>(this DataRow dataRow)
        where TEntity : EntityBase, new()
    {
        TEntity entity = new TEntity();
        ExtensionHelper.TransformDataRowToEntity<TEntity, DataRow>(ref dataRow, ref entity);

        return entity;
    }

    /// <summary>
    /// Converts business object into DataRow.
    /// </summary>
    /// <typeparam name="TEntity">A type that inherits EntityBase.</typeparam>
    /// <param name="dataRow">DataRow object to convert business object into.</param>
    /// <param name="entity">Business object which needs to be converted to DataRow.</param>
    public static void FromEntity<TEntity>(this DataRow dataRow, TEntity entity)
        where TEntity : EntityBase, new()
    {
        ExtensionHelper.TransformEntityToDataRow<TEntity, DataRow>(ref entity, ref dataRow);
    }
}

変換を行う実際のヘルパー メソッド..

/// <summary>
/// Helper methods for transforming data objects into business objects and vice versa.
/// </summary>
/// <remarks>
/// <para>Most important implementation that takes care of universal transformation between business objects and data object.</para>
/// <para>Saves programmers from writing the same old code for every object in the system.</para>
/// </remarks>
public static class ExtensionHelper
{
    /// <summary>
    /// Transforms business object into DataRow.
    /// </summary>
    /// <typeparam name="TEntity">A type that inherits EntityBase.</typeparam>
    /// <typeparam name="TDataRow">A type that inherits DataRow.</typeparam>
    /// <param name="entity">business object which is transformed into DataRow object.</param>
    /// <param name="dataRow">DataRow object which is transformed from business object.</param>
    public static void TransformEntityToDataRow<TEntity, TDataRow>(ref TEntity entity, ref TDataRow dataRow)
        where TDataRow : DataRow
        where TEntity : EntityBase
    {
        IQueryable<DataField> entityFields = entity.GetDataFields();

        foreach (DataColumn dataColoumn in dataRow.Table.Columns)
        {
            if (!dataColoumn.ReadOnly)
            {
                var entityField =
                    entityFields.Single(e => e.DataFieldMapping.MappedField.Equals(dataColoumn.ColumnName, StringComparison.OrdinalIgnoreCase));

                if (entityField.Property.GetValue(entity, null) == null)
                {
                    if (dataColoumn.AllowDBNull)
                    {
                        dataRow[dataColoumn] = System.DBNull.Value;
                    }
                    else
                    {
                        throw new Exception(dataColoumn.ColumnName + " cannot have null value.");
                    }
                }
                else
                {
                    if (entityField.Property.GetType().IsEnum)
                    {
                        dataRow[dataColoumn] = Convert.ToByte(entityField.Property.GetValue(entity, null));
                    }
                    else
                    {
                        dataRow[dataColoumn] = entityField.Property.GetValue(entity, null);
                    }
                }
            }
        }
    }

    /// <summary>
    /// Transforms DataRow into business object.
    /// </summary>
    /// <typeparam name="TEntity">A type that inherits EntityBase.</typeparam>
    /// <typeparam name="TDataRow">A type that inherits DataRow.</typeparam>
    /// <param name="dataRow">DataRow object which is transformed from business object.</param>
    /// <param name="entity">business object which is transformed into DataRow object.</param>
    public static void TransformDataRowToEntity<TEntity, TDataRow>(ref TDataRow dataRow, ref TEntity entity)
        where TDataRow : DataRow
        where TEntity : EntityBase
    {
        IQueryable<DataField> entityFields = entity.GetDataFields();

        foreach (var entityField in entityFields)
        {
            if (dataRow[entityField.DataFieldMapping.MappedField] is System.DBNull)
            {
                entityField.Property.SetValue(entity, null, null);
            }
            else
            {
                if (entityField.Property.GetType().IsEnum)
                {
                    Type enumType = entityField.Property.GetType();
                    EnumConverter enumConverter = new EnumConverter(enumType);
                    object enumValue = enumConverter.ConvertFrom(dataRow[entityField.DataFieldMapping.MappedField]);
                    entityField.Property.SetValue(entity, enumValue, null);
                }
                else
                {
                    entityField.Property.SetValue(entity, dataRow[entityField.DataFieldMapping.MappedField], null);
                }
            }
        }
    }
}

サンプル ビジネス オブジェクトの外観は次のとおりです。カスタム属性に注意してください..

/// <summary>
/// Represents User.
/// </summary>
[TableMapping("Users", "User", "Users")]
public class User : EntityBase
{
    #region Constructor(s)
    /// <summary>
    /// Initializes a new instance of the User class.
    /// </summary>
    public User()
    {
    }
    #endregion

    #region Properties

    #region Default Properties - Direct Field Mapping using DataFieldMappingAttribute

    /// <summary>
    /// Gets or sets the ID value of the AppUser object.
    /// </summary>
    [DataFieldMapping("UserID")]
    [DataObjectFieldAttribute(true, true, false)]
    [NotNullOrEmpty(Message = "UserID From UserDetails Table Is Required.")]
    public override int Id
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the Username value of the User object.
    /// </summary>
    [DataFieldMapping("UserName")]
    [Searchable]
    [NotNullOrEmpty(Message = "Username Is Required.")]
    public string UserName
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the FirstName value of the AppUser object.
    /// </summary>
    [DataFieldMapping("FirstName")]
    [Searchable]
    public string FirstName
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the LastName value of the AppUser object.
    /// </summary>
    [DataFieldMapping("LastName")]
    [Searchable]
    public string LastName
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the WebSite value of the AppUser object.
    /// </summary>
    [DataFieldMapping("WebSite")]
    [ValidURL(Message = "Website is not in Proper Format.")]
    public string WebSite
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the ContactNumber value of the AppUser object.
    /// </summary>
    [DataFieldMapping("ContactNumber")]
    [Searchable]
    public string ContactNumber
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets a value indicating whether AppUser Object is active or inactive.
    /// </summary>
    [DataFieldMapping("IsActive")]
    public bool IsActive
    {
        get;
        set;
    }

    /// <summary>
    /// Gets or sets the BirthDate value of the AppUser object.
    /// </summary>
    [DataFieldMapping("BirthDate")]
    public DateTime? BirthDate
    {
        get;
        set;
    }

    #region Derived Properties

    /// <summary>
    /// Gets the full name of the AppUser
    /// </summary>
    public string FullName
    {
        get { return this.FirstName + " " + this.LastName; }
    }

    /// <summary>
    /// Gets the Age value of the AppUser
    /// </summary>
    public int Age
    {
        get { return this.BirthDate.HasValue ? this.BirthDate.Value.AgeInYears() : 0; }
    }

    #endregion

    #endregion

}

そして、ここに私のクライアントコードがあります..

    /// <summary>
    /// Gets User object by user name.
    /// </summary>
    /// <param name="username">UserName of the user</param>
    /// <returns>User Object</returns>
    public static User GetUserByUsername(string username)
    {
        try
        {
            return Adapter.GetUserByUserName(username)[0].ToEntity<User>();
        }
        catch
        {
            return null;
        }
    }
于 2010-05-27T13:05:30.900 に答える