سؤال

I am having a problem translating a Entity Framework 6 model to a Dto with the below code. I have used this method of converting Entities to Dtos a number of times following reading a CodeProject article by Sacha Barber. The code was working last night so perhaps a change to the model this morning has affected the code.

Just to note the layoutTransator object is correctly loaded from the Unity IoC container.

I have reviewed this Stackoverflow question but it does not really cover my issue.

Entity Model

enter image description here

Loading the entity framework model

    private readonly PortalEntities ctx;
    private readonly IEntityDtoTranlator<Layout, LayoutsDto> layoutTranslator;

    [InjectionConstructor]
    public Dal(IContextFactory<JcbManufacturingPortalEntities> factory,
                    IEntityDtoTranlator<Layout, LayoutsDto> layoutTransator))
    {
        ctx = factory.Create(ConfigurationManager.ConnectionStrings[EntityConnection].ConnectionString, EntityPassword);
        this.layoutTranslator = layoutTransator;
    }

    public List<LayoutsDto> GetDiplayLayouts(string machineAssetName)
    {
        try
        {
            return (ctx.Layouts.Where(m => m.Hardware.AssetName.Equals(machineAssetName))
                        .Select(l => layoutTranslator.TranslatetoDto(l))).ToList();
        }
        catch (Exception ex)
        {

            throw;
        }    

    }

If I break down the load code as below it works. Must be an issue with Linq calling the method.

List<Layout> layout = (ctx.Layouts.Where(m => m.Hardware.AssetName.Equals(machineAssetName))).ToList();
LayoutsDto dto = layoutTranslator.TranslatetoDto(layout.First());

Dto

public class LayoutsDto
{
    [Key]
    public int ID { get; set; }

    [DefaultValue(0)]
    [Range(0,3600000)]
    public int Duration { get; set; }

    [DefaultValue(0)]
    public bool OutOfShift { get; set; }

    public byte FlipOrder { get; set; }

    public List<ScreenDto> Screens { get; set; }
}

Converter

internal class LayoutTranslator<TEntity, TDto> : IEntityDtoTranlator<Layout, LayoutsDto>
{
    public LayoutsDto TranslatetoDto(Layout entity)
    {
        return new LayoutsDto
        {
            Duration = entity.DisplayDuration,
            FlipOrder = entity.FlipOrder,
            ID = entity.ID,
            OutOfShift = entity.IsOutOfShiftScreen
        };
    }

    public Layout TranslateToEntity(LayoutsDto dto)
    {
        return new Layout
        {
            DisplayDuration = dto.Duration,
            FlipOrder = dto.FlipOrder,
            ID = dto.ID,
            IsOutOfShiftScreen = dto.OutOfShift
        };
    }
}

Exception

One point is that the TranslatetoDto(Jmp.Andon.Service.Data.Layout) method is not in the Jmp.Andon.Models.LayoutsDto object

LINQ to Entities does not recognize the method 'Jmp.Andon.Models.LayoutsDto TranslatetoDto(Jmp.Andon.Service.Data.Layout)' method, and this method cannot be translated into a store expression.

   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__a()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.<GetResults>b__9()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at System.Lazy`1.get_Value()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Jmp.Andon.Service.Data.Dal.GetDiplayLayouts(String machineAssetName) in c:\Perforce\Development\JMP v2\Jmp.Display\Jmp.Display.Service\Data\Dal.cs:line 38
هل كانت مفيدة؟

المحلول

You just need to change the context in which your TranslateDto method is being called. At the moment, you are telling L2E that this method is going to be run on at the DB side, however, your method is not translatable to SQL and therefore can't be executed in this way.

You need to force the query to execute that method on the client and to do that you need to switch your query from L2E to LINQ To Objects i.e.

return (ctx.Layouts.Where(m => m.Hardware.AssetName.Equals(machineAssetName))
                   .AsEnumerable() // <-- Here's the switch
                   .Select(l => layoutTranslator.TranslatetoDto(l)));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top