속성이 존재하지 않으면 불평하는 C # 변경 Dapper 동적

c# dapper dynamic

문제

Dapper를 사용하여 SQL 데이터베이스에서 데이터를 가져와 데이터를 '동적'컬렉션으로 반환합니다. 저는 다이나믹 타입의 힘과 "오리 타이핑"의 유연성을 이해합니다. 기본적으로 "오리처럼 쑤셔 넣으면 오리입니다. 오리라고 선언 할 필요가 없습니다."

나는 그것을하지 않는 동적 객체 속성을 얻기 위해 시도하는 경우, 왜 불평하지 않는 이유 그러나, 나는 이해가 안 돼요? 예를 들어 오리 가 아니며 "Qu called (Quack)"이라고 불렀던 것을 가지고 있다면 불평을 기대하는 것이 합리적이라고 생각했을 것입니다. 편집 : 코멘트를 참조하십시오,이 속성을 존재하지 않는 경우 표준 동적 개체 런타임 오류를 제공하기 때문에 Dapper 날주는주는 동적 뭔가를 것으로 보인다.

내가 불평을 토로 할 수있는 방법이 있습니까?

필자가 가지고있는 코드는 '동적'속성을 가져 와서 강하게 입력 된 개체의 해당 속성에 지정하는 일련의 줄입니다. 등록 정보 이름이 항상 일치하지는 않습니다 (레거시 데이터베이스 이름 지정 표준으로 인해). 필드 이름의 철자가 동적 인 경우 현재는 자동으로 실패합니다. 나는 그것이 불평하고 싶다. 나는 코드의 각 단일 라인을 "하드 코딩 된 이름 (hard-coded name) 속성이 동적"/ "불평하지 않으면"/ "5 행으로 다시 작성하지 않아도됩니다."/ "값을 가져 와서 올바른 위치에 넣으십시오. ".

편집 : 여기에 특정 코드, 경우 도움이 ... 잘못된 필드 이름 "result.DecisionLevel"및 런타임 오류가 발생하지 않습니다, 그냥 대상 속성에 Null을 할당합니다

        var results = _connection.Query("usp_sel_Solution", new { IdCase = caseId }, commandType: CommandType.StoredProcedure);
        return results.Select(result => new Solution
        {
            IsDeleted = result.IsDeleted,
            FriendlyName = result.FriendlyName,
            DecisionLevel = (DecisionLevel?)result.DecisionLevel,
        }).ToList();

해결 방법 : Sergey의 대답과 결합 된 대답은 저에게이 해결책을주었습니다 :

internal class SafeDynamic : DynamicObject
{
    private readonly IDictionary<string, object> _source;

    public SafeDynamic(dynamic source)
    {
        _source = source as IDictionary<string, object>;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_source.TryGetValue(binder.Name, out result) == false)
        {
            throw new NotSupportedException(binder.Name);
        }

        return true;
    }

    // I'll refactor this later, probably to an extension method...
    public static IEnumerable<dynamic> Create(IEnumerable<dynamic> rows)
    {
        return rows.Select(x => new SafeDynamic(x));
    }
}

샘플 코드의 유일한 변경 사항은 Dapper의 Query 메서드에 대한 호출을 래핑하는 것입니다.

        var results = SafeDynamic.Create(_connection.Query("usp_sel_Solution", new { IdCase = caseId }, commandType: CommandType.StoredProcedure));

감사.

후손을 위해 Query <T>에 대해 동일한 작업을 수행하는 방법에 대한 링크를 추가하고 편집 25/1/17 "정적 사전의 스레딩 문제를 방지하기위한 개선 사항"을 참고합니다. 여기에 나와있는 솔루션에도 적용됩니다.

수락 된 답변

보유하고있는 소스 오브젝트에 랩핑을 추가하고 그 안에 원하는 동작을 구현할 수 있습니다 (예외를 던지거나 던지거나, 기본값을 제공하거나, 등록 정보 이름을 수정하지 않음). 이 같은:

공용 클래스 WrapperDynamic : DynamicObject {private dynamic _source; public WrapperDynamic (동적 소스) {_source = source; }

public override bool TryGetMember(GetMemberBinder binder, out object result)
{                        
    if (_source.CheckTheProperyExist(binder))
    {
        result = _source.GetProperty(binder);
        return true;
    }
    return false;
}

}

어떤 종류의 소스 객체에 따라 CheckTheProperyExist와 GetProperty를 구현해야합니다.

당신은 당신에게 커버 해줄 것을 선택해야합니다.

return results.Select(x=>new WrapperDynamic(x))
.Select(result => new Solution
        {
            IsDeleted = result.IsDeleted,
            FriendlyName = result.FriendlyName,
            DecisionLevel = (DecisionLevel?)result.DecisionLevel,
        }).ToList();

이 래퍼에서 레거시 이름에 대한 이름 변환을 추가 할 수 있습니다.


인기 답변

예상되는 전체 동작은 생성되는 동적 객체에 따라 다를 수 있습니다.

동적 멤버가 동적 객체의 일부가 아닌 경우 예외를 throw하지 않아도됩니다.

예 :

public class MyDynamic : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
           // I always set the result to null and I return true to tell
           // the runtime that I could get the value but I'm lying it!
           result = null;
           return true;
    }
}


dynamic myDynamic = new MyDynamic();
string text = myDynamic.text; // This won't throw a runtime exception!

아마도 Dapper는 동적 멤버를 얻으려고 시도하지만 멤버가 없으면 불평하지 않으며 이는 의도적으로 설계되었을 수 있습니다.

ExpandoObjectIDictionary<string, object> 를 구현하는 동적 객체이므로 ContainsKey 사용하여 동적 객체에 멤버가 있는지 여부를 효과적으로 확인할 수 ContainsKey .

dynamic expando = new ExpandoObject();
expando.text = "hello world";

if((IDictionary<string, object>)expando).ContainsKey("text")) 
{
    // True
}

BTW, 제 3 자 라이브러리 (또는 제 1 자 라이브러리)가 존재하지 않는 멤버에 액세스 할 때 상처를주지 않는 동적 오브젝트를 구현 한 경우에는 그 반대를 강요 할 수 없습니다. 디자인 결정이기 때문에 함께 살아야합니다.

덕 타이핑 은 문서를 많이 사용하기 때문에 동적 객체가 그런 식으로 작동한다는 것을 안다면 속성 유형의 기본값을 받으면 속성이 설정되지 않은 것을 알 수 있습니다.

dynamic dyn = ...;

// x should be null once it's set and you'll know that
// dyn had no x member...
string x = dyn.x;


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow