Dapper 테이블 값 매개 변수를 속성으로 사용 하시겠습니까?

dapper

문제

나는 이런 식으로 저장된 proc :

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가 호출되지 않는다는 것도 알 수 있습니다.

가능한가요?

감사

수락 된 답변

다음은 코드를 기반으로하는 간단한 예제입니다. AddParameters 가 올바르게 호출되고 값은 저장 프로 시저로 전달됩니다. 참고 사항 : TVP 용으로 DataTable 을 사용하는 경우 라이브러리는 추가 코드가 필요없이 직접 지원합니다.

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");
    }
}

인기 답변

내가 만든 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;
            }
        }
    }

건배



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.