Dapper表值参数作为属性?

时间:2015-04-13 01:29:48

标签: dapper

我有一个像这样的存储过程:

CREATE PROCEDURE [dbo].[Organisation_Insert]
 @OrganisationXId uniqueidentifier
,@Enabled bit
,@Timezone nvarchar(50)
,@MinimumValue float
,@Rules ReminderRuleType READONLY ...

ReminderRuleType是用户定义的类型。

在我的应用中,我有这个:

class OrganisationDTO
    {
        private readonly IOrganisationDocument _orgDoc;
        public long OrganisationId { get { return _orgDoc.OrganisationId; } }
        public Guid OrganisationXId { get { return _orgDoc.OrganisationXId; } }
        public string TimeZone { get { return _orgDoc.TimeZone; } }
        public bool Enabled { get { return _orgDoc.Enabled; } }
        public decimal MinimumValue { get { return _orgDoc.MinimumValue; } }
        public RuleTableValuedParameters Rules { get; private set; }

        public OrganisationDTO(IOrganisationDocument orgDoc)
        {
            _orgDoc = orgDoc;
            Rules = new RuleTableValuedParameters("@Rules", _orgDoc.Rules);
        }
    }

RuleTableValuedParameters实现了具有AddParameters方法的SqlMapper.IDynamicParameters。

执行查询时,永远不会传递@Rules参数(使用SQLProfiler)。我还可以看到从不调用AddParameters。

这可能吗?

由于

2 个答案:

答案 0 :(得分:2)

这是一个基于您的代码的简化示例,显示它工作得很好;正确调用AddParameters,并将值传递给存储过程。作为旁注:如果您使用DataTable作为您的TVP,则该库直接支持,无需其他代码。

public void SO29596645_TvpProperty()
{
    try { connection.Execute("CREATE TYPE SO29596645_ReminderRuleType AS TABLE (id int NOT NULL)"); }
    catch { }
    connection.Execute(@"create proc #SO29596645_Proc (@Id int, @Rules SO29596645_ReminderRuleType READONLY)
                        as begin select @Id + ISNULL((select sum(id) from @Rules), 0); end");
    var obj = new SO29596645_OrganisationDTO();
    int val = connection.Query<int>("#SO29596645_Proc", obj.Rules, commandType: CommandType.StoredProcedure).Single();

    // 4 + 9 + 7 = 20
    val.IsEqualTo(20);

}

class SO29596645_RuleTableValuedParameters : Dapper.SqlMapper.IDynamicParameters {
    private string parameterName;

    public SO29596645_RuleTableValuedParameters(string parameterName)
    {
        this.parameterName = parameterName;
    }


    public void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity)
    {
        Console.WriteLine("> AddParameters");
        SqlCommand lazy = (SqlCommand)command;
        lazy.Parameters.AddWithValue("Id", 7);
        DataTable table = new DataTable {
            Columns = {{"Id", typeof(int)}},
            Rows = {{4}, {9}}
        };
        lazy.Parameters.AddWithValue("Rules", table);
        Console.WriteLine("< AddParameters");
    }
}
class SO29596645_OrganisationDTO
{
    public SO29596645_RuleTableValuedParameters Rules { get; private set; }

    public SO29596645_OrganisationDTO()
    {
        Rules = new SO29596645_RuleTableValuedParameters("@Rules");
    }
}

答案 1 :(得分:2)

这是我创建的完整工作DynamicParameter:

 public class OrganisationDynamicParameter : SqlMapper.IDynamicParameters
{
    private readonly IOrganisation _orgModel;

    public OrganisationDynamicParameter(IOrganisation orgModel)
    {
        _orgModel = orgModel;
    }

    public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
        SqlParameter p;
        var sqlCommand = (SqlCommand)command;
        sqlCommand.CommandType = CommandType.StoredProcedure;

        p = sqlCommand.Parameters.Add("@OrganisationXId", SqlDbType.UniqueIdentifier);
        p.Value = _orgModel.OrganisationXId;
        p = sqlCommand.Parameters.Add("@Enabled", SqlDbType.Bit);
        p.Value = _orgModel.Enabled;
        p = sqlCommand.Parameters.Add("@Timezone", SqlDbType.NVarChar, 50);
        p.Value = _orgModel.TimeZone;
        p = sqlCommand.Parameters.Add("@MinimumValue", SqlDbType.Float);
        p.Value = _orgModel.MinimumValue;

        List<SqlDataRecord> ruleList = _orgModel.Rules.Select(MapRuleData).ToList();
        if (ruleList.Count > 0)
        {
            p = sqlCommand.Parameters.Add("@Rules", SqlDbType.Structured);
            p.Direction = ParameterDirection.Input;
            p.TypeName = "ReminderRuleType";
            p.Value = ruleList;
        }
    }

    protected SqlDataRecord MapRuleData(IReminderRule value)
    {
        var rec = new SqlDataRecord(new[]
        {
            new SqlMetaData("RuleId", SqlDbType.BigInt),
            new SqlMetaData("OrganisationId", SqlDbType.BigInt),
            new SqlMetaData("Name", SqlDbType.NVarChar, 200),
            new SqlMetaData("OffsetDays", SqlDbType.Int),
            new SqlMetaData("SubjectTemplate", SqlDbType.NVarChar, -1),
            new SqlMetaData("BodyTemplate", SqlDbType.NVarChar, -1)
        });

        rec.SetInt64(0, value.RuleId);
        rec.SetInt64(1, value.OrganisationId);
        rec.SetString(2, value.Name);
        rec.SetInt32(3, value.OffsetDays);
        rec.SetString(4, value.SubjectTemplate);
        rec.SetString(5, value.BodyTemplate);
        return rec;
    }
}

我这样使用它:

public IOrganisation CreateOrganisation(IOrganisation organisation)
    {
        var dtoOrg = new OrganisationDynamicParameter(organisation);
        return ExecuteSPReturningOrganisation("Organisation_Insert", dtoOrg);
    }

    protected IOrganisation ExecuteSPReturningOrganisation(string query, object parameters)
    {
        using (IDbConnection con = ConnectionFactory.CreateOpenConnection())
        {
            using (
                SqlMapper.GridReader multi = con.QueryMultiple(query, parameters,
                    commandType: CommandType.StoredProcedure))
            {
                OrganisationModel org = multi.Read<OrganisationModel>().SingleOrDefault();
                if (org != null)
                {
                    org.Rules = multi.Read<ReminderRuleModel>().ToArray();
                }

                return org;
            }
        }
    }

干杯