Home > database >  EFcore Joining InMemory Table for duplication of entry
EFcore Joining InMemory Table for duplication of entry

Time:10-27

Contrary to most questions about joining to an inmemory table in efcore, my objective is not to reduce the amount of records returned, but to actually increase it.

I have an object that has an ins and an outs property.

because of the project it is on, theses need to be in the same object. but in my case, I need to consider both of these properties as seperate entities. (kindof how you would use them in a pivot table in excel)

my immediate objective is to transform the {ins:x, outs:y} into two lines : {type:'ins', value:x} and {type:'outs', value:y}

The reason I need them seperate is because I'm later joining on other table differently depending on the type.

in SQL, this is how I would do things :

SELECT CASE WHEN t.type = 'ins' THEN d.ins ELSE d.outs END, t.type
FROM Data d
JOIN (VALUES ('ins'), ('outs')) as t (type) on 1=1;

(VALUES (1,0), (3,5)) as d (ins, outs) instead of Data d can be used as an exemple.

I need to do that with linq in order to "duplicate" all lines (with specific data attached).

These lines are then used later to make other joins.

What I would have liked is something like that :

var q = from d in data
        from type in new string[] {"ins","outs"}
        select new {type, value = (type == "ins" ? d.ins : d.outs)}

but it isn't valid.

the error I get with that is :

The LINQ expression 'd => string[] { "ins", "outs", }' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

creating the array outside doesn't change anything, the error stays the same (well, the expression in the error changes, but not the main message itself)

is there a way to do that ? or do I have no other choice than creating a dummy table in the database containing my ins and outs to have the join be possible directly (if that is the only choice, what would be the best way to add that ?)

CodePudding user response:

Hi and welcome to StackOverflow community!

You are on the right way and you only need to correct a thing in your code:

The problem is that you haven't named the variable containing data in the anonymous type:

var q = from d in data
        from type in new string[] {"ins","outs"}
        select new {
           type, 
           datas = type == "ins" ? d.ins : d.outs 
        };

EDIT:

The error is saying that the creation of the string array cannot be translated into SQL language...

I thought that also 'Data' table was in-memory, but I think that you cannot join 'concrete' (db) tables with in-memory ones, so I suggest to force linq to load the data before joining calling ToList() to the db table (as the error suggests):

var q = from d in Data.Tolist()
        from type in new string[] {"ins","outs"}
        select new {
           type, 
           value = type == "ins" ? d.ins : d.outs 
        };

If loading the enitire table into memory is a problem you can create the "ins/outs" table inside the DB and join with it...

CodePudding user response:

I would propose extension linq2db.EntityFrameworkCore (disclaimer: I'm one of the creators).

Nothing in query should be changed, just add call ToLinqToDB():

var q = from d in data
        from type in new string[] {"ins","outs"}
        select new {type, value = (type == "ins" ? d.ins : d.outs)};

q = q.ToLinqToDB();

It should create desired SQL.

  • Related