Reputation: 24053
I have this problem and I really don't know how to solve it. I asked two questions before abput this problem but didn't get to figure the right answer for my situation. Here is the problem in details. I have an interface and default implementation:
public interface IEntityPriceDefinition
{
PriceDefinition PriceDefinition { get; }
bool IsMatch(long additionId);
bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId);
bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
long additionId);
bool IsMatch(long? entityId, Task3 task);
bool IsMatch(long? entityId, Task3 task, long additionId);
}
public class EntityPriceDefinition : IEntityPriceDefinition
{
private PriceDefinition _PriceDefinition;
private Func<long?, bool> _IsEntityIdMatch;
private Func<Task3, long?> _TaskValue;
public PriceDefinition PriceDefinition { get { return _PriceDefinition; } }
internal EntityPriceDefinition(
PriceDefinition priceDefinition,
Func<long?, bool> isEntityIdMatch,
Func<Task3, long?> taskValue)
{
_PriceDefinition = priceDefinition;
_IsEntityIdMatch = isEntityIdMatch;
_TaskValue = taskValue;
}
public bool IsMatch(long additionId)
{
return PriceDefinition.AdditionsPrices.Any(x => x.AdditionId == additionId);
}
private bool IsMatch(long? inviterId, long? routeId, long? luggageTypeId)
{
bool isMatch = inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue;
if (isMatch)
{
if (PriceDefinition.InviterId.HasValue && inviterId.HasValue)
{
if (PriceDefinition.InviterId.Value != inviterId.Value) { isMatch = false; }
}
if (PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue)
{
if (PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) { isMatch = false; }
}
if (PriceDefinition.RouteId.HasValue && routeId.HasValue)
{
if (PriceDefinition.RouteId.Value != routeId.Value) { isMatch = false; }
}
}
return isMatch;
}
public bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId)
{
return _IsEntityIdMatch(entityId) && IsMatch(inviterId, routeId, luggageTypeId);
}
public bool IsMatch(long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
long additionId)
{
return IsMatch(entityId, inviterId, routeId, luggageTypeId) && IsMatch(additionId);
}
public bool IsMatch(long? entityId, Task3 task)
{
bool isMatch = _IsEntityIdMatch(_TaskValue(task)) &&
IsMatch(task.InviterId, task.RouteId, task.LuggageTypeId);
for (int i = 0; i < PriceDefinition.Rules.Count && isMatch == true; i++)
{
object value = task.GetFieldObjectValue(PriceDefinition.Rules[i].FieldName);
isMatch = PriceDefinition.Rules[i].IsMatch((value ?? string.Empty).ToString());
}
return isMatch;
}
public bool IsMatch(long? entityId, Task3 task, long additionId)
{
return IsMatch(entityId ,task) && IsMatch(additionId);
}
}
I also have 3 classes that implement IEntityPriceDefinition
using the default implementation. Here are two of those classes (the third is the same):
public class CustomerPriceDefinition : IEntityPriceDefinition, IDataEntity
{
private IEntityPriceDefinition _EntityPriceDefinition;
public virtual long PriceDefinitionId { get; set; }
public virtual long CustomerId { get; set; }
public virtual PriceDefinition PriceDefinition { get; set; }
public CustomerPriceDefinition()
{
_EntityPriceDefinition = new EntityPriceDefinition(
PriceDefinition,
entityId => entityId.HasValue && entityId.Value == CustomerId,
t => t.CustomerId);
}
public bool IsMatch(long additionId)
{
return _EntityPriceDefinition.IsMatch(additionId);
}
public bool IsMatch(long? customerId, long? inviterId, long? routeId, long? luggageTypeId)
{
return _EntityPriceDefinition.IsMatch(customerId, inviterId, routeId, luggageTypeId);
}
public bool IsMatch(long? customerId, long? inviterId, long? routeId, long? luggageTypeId,
long additionId)
{
return _EntityPriceDefinition.IsMatch(customerId, inviterId, routeId, luggageTypeId,
additionId);
}
public bool IsMatch(long? customerId, Task3 task)
{
return _EntityPriceDefinition.IsMatch(customerId, task);
}
public bool IsMatch(long? customerId, Task3 task, long additionId)
{
return _EntityPriceDefinition.IsMatch(customerId, task, additionId);
}
}
public class WorkerPriceDefinition : IEntityPriceDefinition, IDataEntity
{
private IEntityPriceDefinition _EntityPriceDefinition;
public virtual long PriceDefinitionId { get; set; }
public virtual long WorkerId { get; set; }
public virtual PriceDefinition PriceDefinition { get; set; }
public WorkerPriceDefinition()
{
_EntityPriceDefinition = new EntityPriceDefinition(
PriceDefinition,
entityId => entityId.HasValue && entityId.Value == WorkerId,
t => t.WorkerId);
}
public bool IsMatch(long additionId)
{
return _EntityPriceDefinition.IsMatch(additionId);
}
public bool IsMatch(long? workerId, long? inviterId, long? routeId, long? luggageTypeId)
{
return _EntityPriceDefinition.IsMatch(workerId, inviterId, routeId, luggageTypeId);
}
public bool IsMatch(long? workerId, long? inviterId, long? routeId, long? luggageTypeId,
long additionId)
{
return _EntityPriceDefinition.IsMatch(workerId, inviterId, routeId, luggageTypeId,
additionId);
}
public bool IsMatch(long? workerId, Task3 task)
{
return _EntityPriceDefinition.IsMatch(workerId, task);
}
public bool IsMatch(long? workerId, Task3 task, long additionId)
{
return _EntityPriceDefinition.IsMatch(workerId, task, additionId);
}
}
I have also repository interface and default implementation for those classes:
public interface IEntityPriceDefinitionRepository<T> : IRepository<T>
where T : class, IEntityPriceDefinition, IDataEntity
{
IEnumerable<T> GetMatchPrices(
Guid companyId, bool? isSuggested, bool? isValid,
long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
Expression<Func<T, object>>[] includes);
IEnumerable<T> GetMatchPrices(
Guid companyId, bool? isSuggested, bool? isValid,
long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
Expression<Func<T, object>>[] includes);
}
public class EntityPriceDefinitionRepository<T> : BaseRepository<T>,
IEntityPriceDefinitionRepository<T> where T : class,IEntityPriceDefinition, IDataEntity
{
private IEnumerable<T> GetMatchPrices(
Guid companyId, bool? isSuggested, bool? isValid,
Expression<Func<T, bool>> isMatch,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
Expression<Func<T, object>>[] includes)
{
var filters = new Expression<Func<T, bool>>[]{
x => x.PriceDefinition.CompanyId == companyId,
x => x.PriceDefinition.IsDeleted == false,
x => !isValid.HasValue || x.PriceDefinition.IsValid == isValid.Value,
x => !isSuggested.HasValue || x.PriceDefinition.IsSuggested == isSuggested.Value,
isMatch
};
return GetQuery(filters, orderBy, includes);
}
public IEnumerable<T> GetMatchPrices(
Guid companyId, bool? isSuggested, bool? isValid,
long? entityId, long? inviterId, long? routeId, long? luggageTypeId,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
Expression<Func<T, object>>[] includes)
{
return GetMatchPrices(companyId, isSuggested, isValid,
////////////////// THIS CAUSE THE EXCEPTION MENTIONED BELOW: //////////////////
x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId),
orderBy, includes);
}
public IEnumerable<T> GetMatchPrices(
Guid companyId, bool? isSuggested, bool? isValid,
long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
Expression<Func<T, object>>[] includes)
{
return GetMatchPrices(companyId, isSuggested, isValid,
////////////////// THIS CAUSE THE EXCEPTION MENTIONED BELOW: //////////////////
x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId, additionId),
orderBy, includes);
}
}
And the classes repository classes are just:
public class CustomerPriceDefinitionRepository :
EntityPriceDefinitionRepository<CustomerPriceDefinition> { }
public class WorkerPriceDefinitionRepository :
EntityPriceDefinitionRepository<WorkerPriceDefinition> { }
The problem happend when I call CustomerPriceDefinitionRepository's GetMatchPrices method. It always ends up with exception about the method that marked above:
LINQ to Entities does not recognize the method 'Boolean IsMatch(System.Nullable
1[System.Int64], System.Nullable
1[System.Int64], System.Nullable1[System.Int64], System.Nullable
1[System.Int64])' method, and this method cannot be translated into a store expression.
Ladislav Mrnka's answered me here to use model defined functions but I want all my code to be in its classes and not in xml's. In addition, this code doesn't relevant to the huge scope that the edmx uses. In addition, I believe that in order to use model defined functions I will have to define 3 methods - one IsMatch for each sub class of IEntityPriceDefinition.
I really don't know how to solve this problem and what is the best solution for such case especially for such non-simple structure. I will appriciate any help.
Upvotes: 1
Views: 1595
Reputation: 24053
I added a static method in EntityPriceDefinition :
public static Expression<Func<CustomerPriceDefinition, bool>> IsMatchExpression(
long? entityId, long? inviterId, long? routeId, long? luggageTypeId, long additionId)
{
return x =>
(entityId.HasValue && entityId.Value == x.CustomerId) &&
(inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue) &&
!(
(x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
x.PriceDefinition.InviterId.Value != inviterId.Value) ||
(x.PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue &&
x.PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) ||
(x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
x.PriceDefinition.InviterId.Value != inviterId.Value)
) &&
x.PriceDefinition.AdditionsPrices.Any(a => a.AdditionId == additionId);
}
That way the expression knows how to transform it to query.
Upvotes: 1