Putting interface behind properties with same name but different types

半腔热情 提交于 2019-12-25 06:29:06

问题


I have a around 50 databases that have 150 tables each and working on a search mechanism that would allow to query the tables that have specific columns. Most database structures are similar so idea was to generate EF entities and put interfaces behind the entities generated if tables that they are being generated from have specific columns, so that I could later query then on that column.

After doing this I ran into unexpected problem on some tables column I am trying to map is Long while on others it's Decimal (oracle) and sometimes it's Nullable and sometimes it's not.

One solution I can see to this is to add interface without any properties and when at runtime determine specific type of that column, before running the query.

Is there a way to add some type on interface for property that might be more than one type so compiler wouldn't complain about not being implemented? object does not work, let me know if you need code examples as question is somewhat complicated.

Mechanism I intend to use on entities:

public static class ExpressionExtensions
{
    public static IQueryable<T> ApplySearch<T>(this IQueryable<T> queryable, SearchModel search) where T : class 
    {
        if (search != null && search.PolicyNumber.HasValue && typeof(IPolicyNumber).IsAssignableFrom(queryable.ElementType))
        {
           queryable = queryable.SearchByPolicyNumber(search);
        }

        return queryable;
    }

    public static IQueryable<IPolicyNumber> SearchByPolicyNumber<IPolicyNumber>(this IQueryable<IPolicyNumber> queryable, SearchModel search)
    {
        var policyNumberParameterLambda = Expression.Parameter((typeof(IPolicyNumber)));
        var policyNumberColumnLambda = Expression.Property(policyNumberParameterLambda, "POLICY_NO");
        var lambda = Expression.Lambda<Func<IPolicyNumber, bool>>(
          Expression.Equal(policyNumberColumnLambda,
              Expression.Convert(Expression.Constant(search.PolicyNumber), policyNumberColumnLambda.Type)
          ), policyNumberParameterLambda);
        return queryable.Where(lambda);
    }
}

回答1:


figured it out myself

Interface that gets put on entities has to change from this

public interface IUniqueId
{
   long UNIQUE_ID { get; set; }
}

to this

public interface IUniqueId<T> : IUniqueId
{
   T UNIQUE_ID { get; set; }
}

public interface  IUniqueId
{
}

and then where interface is put on entity

from

public partial class QUOTE_HOUSE : IUniqueId
{
   public long UNIQUE_ID { get; set; }
...
}

to

public partial class QUOTE_HOUSE : IUniqueId<long>
{
    public long UNIQUE_ID { get; set; }
....
}

and T4 code that generates interfaces changed from

public string EntityClassOpening(EntityType entity)
{
    var stringsToMatch = new Dictionary<string,string> { { "POLICY_NO", "IPolicyNumber" }, { "UNIQUE_ID", "IUniqueId" } };
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}{4}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
        stringsToMatch.Any(o => entity.Properties.Any(n => n.Name == o.Key)) ? " : " + string.Join(", ", stringsToMatch.Join(entity.Properties, l => l.Key, r => r.Name, (l,r) =>  l.Value)) : string.Empty);
}

to

public string EntityClassOpening(EntityType entity)
{
    var stringsToMatch = new Dictionary<string,string> { { "POLICY_NO", "IPolicyNumber" }, { "UNIQUE_ID", "IUniqueId" } };
    return string.Format(
        CultureInfo.InvariantCulture,
        "{0} {1}partial class {2}{3}{4}",
        Accessibility.ForType(entity),
        _code.SpaceAfter(_code.AbstractOption(entity)),
        _code.Escape(entity),
        _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
        stringsToMatch.Any(o => entity.Properties.Any(n => n.Name == o.Key)) ? " : " + string.Join(", ", stringsToMatch.Join(entity.Properties, l => l.Key, r => r.Name, (l,r) => string.Format("{0}<{1}{2}>", l.Value,  r.TypeUsage.EdmType.Name, r.Nullable && r.TypeUsage.EdmType.Name!="String" ? "?" : ""))) : string.Empty);
}

Generics FTW indeed...

Hope this saves you some time.



来源:https://stackoverflow.com/questions/37812584/putting-interface-behind-properties-with-same-name-but-different-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!