Not supported in LINQ to Entities - c#

Everytime I use the Include extension, it would return an error when a value from included entity is used in the WHERE CLAUSE.
I included the System.Data.Entity which is the common answer but still have the same issue.
Model:
public partial class business_partner
{
public int id { get; set; }
public string accountid { get; set; }
}
public partial class order
{
public int id { get; set; }
public string doc_number { get; set; }
public int vendor_id { get; set; }
public int status { get; set; };
[ForeignKey("vendor_id")]
public virtual business_partner businessPartnerVendor { get; set; }
}
public IQueryable<order> GetOrder()
{
return (context.order);
}
Query:
_orderService.GetOrder()
.Include(a => a.businessPartnerVendor)
.Where(o => o.doc_number == "Order Number"
&& o.businessPartnerVendor.accountid == "TEST"
&& o.status > 2 && o.status != 9).Count() > 0
Exception:
The specified type member 'businessPartnerVendor' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Alas you forgot to write your requirement. Your code doesn't do what you want, so I might come to the incorrect conclusion, but looking at your code, it seems that you want the following:
Tell me whether there are Orders, that
- have a value of DocNumber that equals "Order_Number",
- AND that are orders of a BusinessPartnerVendor with a value of AccountId equal to "TEST",
- AND have a value of Status which is more than 2 and not equal to 9.
The part "Tell me whether there are Orders that", was deducted by the fact that you only want to know whether Count() > 0
Your Count would have joined all elements, included all columns of BusinessPartnerVendor, removed all rows that didn't match your Where, and counted how many joined items were left. That integer value would be transferred, after which your process would check whether the value is larger than zero.
One of the slower parts of a database query is the transport of the selected data to from the Database Management System to your local process. Hence it is wise to limit the amount of transferred data.
Quite often I see people using Include to get the items that are stored in a different table (quite often a one-to-many). This will select the complete row. From the businessPartnerVendor, you only want to use property AccountId. So why select the complete object?
In entity framework use Select to select properties you want to query. Only use Include if you want to update the fetched data.
bool areTestOrdersAvailable = orderService.GetOrder()
.Where(order => order.doc_number == "Order Number"
&& order.businessPartnerVendor.accountid == "TEST"
&& order.status > 2 && order.status != 9)
.Any();
Because of the virtual keyword in your classes (ans maybe some fluent API), entity framework knows about the one-to-many relation and will perform the correct join for you. It will only use SQL "TAKE 1" to detect whether there are any elements. Only one Boolean is transferred
Some Advices about entity framework
It is good practice to stick as much as possible to the entity framework code first conventions The more you do this, the less Attributes and Fluent API is needed. There will also be less discrepancy between the way Microsoft's usage of identifiers for classes, fields, properties, methods, etc and yours.
In entity framework, all columns of a table are represented by non-virtual properties, the virtual properties represent the relations between tables (one-to-many, many-to-many, ...)
My advice would be: add the foreign keys to your classes, and stick to one identifier to describe one row in your tables.
So decide whether to use business_partner or BusinessPartnerVendor if they are in fact the same kind of thing
Add the foreign key:
// Every Order is the Order of exactly one BusinessPartner, using foreign key (one-to-many)
public int BusinessPartnerId {get; set;}
public virtual BusinessPartner BusinessPartner {get; set;}
This has the advantage, that if you want to select the Ids of all BusinessPartners that have one or more Orders that ..., you don't have to perform a join:
var businessPartnerIds = myDbContext.Orders
.Where(order => ...)
.Select(order => order.BusinessPartnerId)
.Distinct();
Only one database table will be accessed

Related

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'Database operation expected to affect 1 row(s) but actually affected 2 row(s)

I received this error once I try to update table with the same value (carNumber), my condition is to update where the actual return date field is null.
For some reason it's look like the query return 2 rows, but actually there is only one. I'm using EF. This is the function:
the error - print screen
Code:
public void updateStatus(int carNumber1, string actualDate1)
{
DateTime accReturn = DateTime.Parse(actualDate1);
var orderCar1 = db.CarRentalFields.FirstOrDefault(carNum =>
(carNum.CarNumber == carNumber1 && carNum.ActualReturnDate == null));
orderCar1.ActualReturnDate = accReturn;
db.SaveChanges();
}
The error happens when trying to call db.saveChanges().
the table from the db, the car number is 1000 - print screen
modelBuilder.Entity pic
Please let me know how can I solve this issue.
problem solved by add a new column to the car_rental_fields table, id column that include Identity.
as I understand from here and from the web, there is an issue with complicated pk.
in my solution the id isn't a primary key, but it's make the logic for linq to update the correct column.
thanks' for all the people that involved in this issue.
This error occurs when EF cannot resolve the PK for your entity. In most cases for simple entities, EF conventions can work out the PK, but in your case you are using a composite key so this needs to be configured. Depending on how you are mapping your entities you can do this either in:
an EDMX
in the DbContext.OnModelCreating
using an EntityTypeConfiguration declaration
using attributes within the entity itself
Since we don't know how your entities are configured, you can verify this as the cause by using the attribute approach within your entity as a test. If you are using an EDMX the entity classes will be generated so you will want to replace this with configuration within the EDMX. (Cannot really help you there because I don't use the dang things :D )
You will probably have something like:
public class CarRentalFields
{
[Column("start_day")]
public DateTime StartDay { get; set; }
[Column("return_date")]
public DateTime ReturnDate { get; set; }
[Column("user_id")]
public int UserId { get; set; }
[Column("car_number")]
public DateTime CarNumber { get; set; }
// ... more columns...
}
You may even have a [Key] attribute on one of these fields, such as CarNumber. If there is a PK mapped in the entity the issue is that it isn't specific enough to uniquely identify the row. When EF goes to update one entity, it is checking for, and expecting to update only one row in the table. It's finding more than one row will be affected so it fails.
Append the attributes for the [Key] with the column order so it is recognized as a composite key.
public class CarRentalFields
{
[Key, Column(Name="start_day", Order=1)]
public DateTime StartDay { get; set; }
[Key, Column(Name="return_date", Order=2)]
public DateTime ReturnDate { get; set; }
[Key, Column(Name="user_id", Order=3)]
public int UserId { get; set; }
[Key, Column(Name="car_number", Order=4)]
public DateTime CarNumber { get; set; }
// ... more columns...
}
Provided these 4 columns are guaranteed to be a unique constraint on the table, EF will be satisfied when only one row is updated when it builds it's UPDATE SQL statement.
Note again that if this works and you are using an EDMX, you will need to review and modify your EDMX mapping to make the appropriate changes since that entity class could be regenerated, losing your extra attributes. (I believe the generated entity classes from an EDMX have a comment header warning you that it is a generated class, so that is an indicator to watch out for.)
Update:
My primary suspect in this would be that the table does not actually have a matching PK defined, either running a different PK combination, or more likely no PK given the nature of those fields. EF can operated on tables that have no PK defined, but it does require a Key definition that ensures records can be uniquely identified. The error you are seeing happens when that key definition is not unique enough. (I.e. if you are updating car 1, and selecting a row that has:
car_number = 1, start_day = 2021-11-21, return_day = 2021-11-22, user_id = 0 The issue is that more than one row has that combination in the DB. If the DB you are checking doesn't have more than one matching row then your application is almost certainly pointing at a different database than you are checking.
Things you can do to verify this:
get the runtime connection string and see if it matches the DB you are checking:
Before you run your query, add the following:
// EF6
var connectionString = db.Database.Connection.ConnectionString;
// EF Core 5
var connectionString = db.Database.GetConnectionString();
Have a look at the data you are actually querying:
.
var cars = db.CarRentalFields.Where(carNum =>
(carNum.CarNumber == carNumber1 && carNum.ActualReturnDate == null)).ToList();
While this query might return only 1 record, that is not the cause of the problem. What you want is the CarNumber, StartDate, ReturnDate, and UserId for this record:
var car = db.CarRentalFields
.Where(carNum => carNum.CarNumber == carNumber1
&& carNum.ActualReturnDate == null)
.Select(x => new
{
x.CarNumber,
x.StartDay,
x.ReturnDate,
x.UserId
}).Single(); // Expect our 1 record here...
var cars = db.CarRentalFields
.Where(x => x.CarNumber == car.CarNumber
&& x.StartDay == car.StartDay
&& x.ReturnDate == car.ReturnDate
&& x.UserId == car.UserId)
.ToList(); // Get rows that match our returned Key fields.
These queries select the assumed PK values for the car record you mean to update, then search cars for matching records with the expected Key fields. My money would be on that while the top query returns 1 record, the bottom query returns two rows, meaning while only 1 record has a #null ActualReturnDate value, your Key is not unique enough for the contents of this table.

Entity Framework - Disctinct by property

I have this code:
var models = await _assignment
.Include(a => a.Rule)
.Include(a => a.User)
.Select(x => new AssignmentResponse
{
Id = x.User.Id,
RuleId = x.RuleId ?? -1
})
.ApplyFilterAndPaginationAsync(_webQueryProcessor, request.Options, cancellationToken);
I am trying to get the first assignment for each user (there can be many ruleIds for one userId, but I only want the first).
My attempt (not working):
var models = await _assignment
.Include(a => a.Rule)
.Include(a => a.User)
.Distinct(a => a.User.Id)
.Select(x => new AssignmentResponse
{
Id = x.User.Id,
RuleId = x.RuleId ?? -1
})
.ApplyFilterAndPaginationAsync(_webQueryProcessor, request.Options, cancellationToken);
How can I achieve that without loading them all into memory?
So you have a table of Users and a table of Assignments, and there is a one-to-many relation between Users and Assignments: every User has zero or more Assignments, every Assignment belongs to exactly one User, namely the User that the foreign key refers to.
You also have a table of Rules. There is a relation between Assignments and Rules. I'm not sure about the kind of relation : does every Assignment have exactly one Rule? (one-to-many: Rules have zero or more Assignments, Assignment has foreign key to rule).
Or is there a many-to-many relation: every Assignment has zero or more Rules, and every Rule is a Rule in zero or more Assignments.
Because this is not part of your question, I won't go deep into this.
If you have followed the entity framework conventions, you will have classes like this:
public class User
{
public int Id {get; set;}
public string Name {get; set;}
... // other properties
// every User has zero or more Assignments (one-to-many)
public virtual ICollection<Assignment> Assignments {get; set;}
}
public class Assignment
{
public int Id {get; set;}
public string Name {get; set;}
public DateTime Date {get; set;}
... // other properties
// every Assignment is the assignment of exactly one user, using foreign key:
public int UserId {get; set;}
public virtual User User {get; set;}
// One-To-Many: Every assignment has one Rule using foreign key
public int RuleId {get; set;}
public virtual Rule Rule {get; set;}
// alternative: many-to-many: every assignment has zero or more Rules
public virtual ICollection<Rule> Rules {get; set;}
}
In Entity Framework, the non-virtual properties represent the columns of the tables; the virtual properties represent the relations between the tables (one-to-many, many-to-many).
The foreign key UserId is a real column in table Assignments, hence it is non-virtual. User is not a column in Assignment, but a relation with Assignment, hence it is declared virtual.
For completeness the DbContext:
public class WorkDbContext : DbContext
{
public DbSet<User> Users {get; set;}
public DbSet<AssignMent> Assignments {get; set;}
public DbSet<Rule> Rules {get; set;}
...
}
Because I followed the entity framework conventions, this is all that entity framework needs to detect the tables, the columns of the tables and the relations between the tables (one-to-many, many-to-many), including the foreign keys. Only if you want to deviate from the conventions, especially different identifiers, you need to use Attributes or fluent API.
I am trying to get the first assignment for each user
Problem: what is the first assignment?
Is that the assignment with the oldest Date?
is that the assignment with the lowest Id?
is that the assignment that comes first in the database? (fairly unpredictable)
Use virtual ICollections
When using entity framework to fetch data in a one-to-many relation, it is usually easier to use the virtual properties. Entity framework knows your relations, and creates the proper (Group-)Join for you.
using (var dbContext = new WorkDbContext())
{
var usersWithTheirFirstAssignment = dbContext.Users.Select(user => new
{
// Select only the User properties that you plan to use
Id = user.Id,
Name = user.Name,
...
// Get the "first" Assignment
FirstAssignment = ... // TODO: implement
})
.ToList();
}
To get the FirstAssignment, if that is the one with the oldest Date, OrderBy Date, before selecting the properties:
FirstAssignment = user.Assignments.OrderBy(assignment => assignment.Date)
.Select(assignment => new {...})
.FirstOrDefault();
Or if the first assignment is the one with the lowest Id:
FirstAssignment = user.Assignments.OrderBy(assignment => assignment.Id)
.Select(assignment => new {...})
.FirstOrDefault();
Or if the first assignment is just the one that is first in the database:
FirstAssignment = user.Assignments.Select(assignment => new {...})
.FirstOrDefault();
if you have a one-to-many relation, and you want for every "one" item its "many" subItem, start at the "one" in a Select and use the virtual ICollection to fetch the "many" subItems.
If, on the other hand, you want items, each item with its one and only parent that the foreign key refers to, start at the "many" side, and use the virtual property to select the "one" side properties.
Intermezzo: Why select only the properties that you plan to use?
Database management systems are extremely optimized in selecting data. One of the slower parts of the query is the transfer of the selected data from the DBMS to your local process. Hence it is wise to limit the amount of selected data as much as possible.
If you use Include to select related classes, the complete related subclass is selected, inclusive the foreign keys.
So if User [10] has 1000 Assignments, every Assignment will have a foreign key UserId with value 10. You will be transferring this same number 10 more than 1000 times. What a waste of processing power.
Another reason to use Select if you don't plan to change the fetched data, is that every DbContext has a ChangeTracker. If you fetch an table row without Select, the fetched object is stored in the ChangeTracker, together with a copy. You get a reference to the original. If you change values, the values of the original in the ChangeTracker are changed. When you use SaveChanges, all Originals in the ChangeTracker are compared by value with the copy, to see which items need to be updated.
So if you fetch 1000 users, your ChangeTracker will contain 1000 originals and 1000 copies. If you only change one before calling SaveChanges, the code must check every non-virtual property of each of these 1000 Users, while only one user will be changed. What a waste of processing power!
When querying data, always use Select and select only the properties that you actually plan to use. Only fetch complete classes or use Include if you plan to change the fetched data.
So in the Select above:
FirstAssignment = user.Assignments.OrderBy(...)
.Select(assignment => new
{
// Select only the Assignment properties that you plan to use
Id = assignment.Id,
Date = assignment.Date,
// don't Select the foreign key, you already know the value:
// UserId = assignment.UserId
Rule = new
{
// you know the drill by now: only the rule properties that you plan to use!
Id = assignment.Rule.Id,
Name = assignment.Rule.Name,
...
},
})
.FirstOrDefault(),
Alternative: use the foreign key in the Select
Although using the virtual ICollection seems to me the most intuitive solution, you could also use the foreign key to select the FirstAssignment:
var usersWithTheirFirstAssignment = dbContext.Users.Select(user => new
{
Id = user.Id,
Name = user.Name,
...
FirstAssignment = dbContext.Assignments
.Where(assignment => assignment.UserId == user.Id)
.Orderby(...)
.Select(...)
.FirstOrDefault(),
}
OrderBy and Select are the same as above. Entity Framework will create a GroupJoin similar to the one when using the virtual ICollection.
But I want to do the (Group-)Join myself!
Some people don't trust entity framework. They don't use the virtual ICollection, but prefer do the GroupJoin themselves. If you want to do that, you need to do something like:
// GroupJoin Users and Assignments:
var usersWithTheirFirstAssignment = dbContext.Users.GroupJoin(dbContext.Assignments,
user => user.Id, // from every user take the primary key
assignment => assignment.UserId, // from every assignment take the foreign key to the user
// parameter resultSelector: from every User and its zero or more assignments, make one new
(user, assignmentsOfThisUser) => new
{
Id = user.Id,
Name = user.Name,
...
// the first assignment: order and select like described above
FirstAssignment = assignmentsOfThisUser.OrderBy(...)
.Select(...)
.FirstOrDefault(),
}
Try to use group by
var models = await _assignment
.Include(a => a.Rule)
.Include(a => a.User)
.GroupBy(a => a.User.Id)
.Select(x => new AssignmentResponse
{
Id = x.Key,
RuleId = x.FirstOrDefault().RuleId ?? -1
})
.ApplyFilterAndPaginationAsync(_webQueryProcessor, request.Options, cancellationToken);
Moreover, I think that you don't need to include Rule? If you do not reference any field of it.

NotMapped property causes all properties load in select statement in EF Core

I use EF Core 5 in a project, one of my entities contains a NotMapped property that mixed two properties of the entity, I expect in the select statement only properties that contain in the select statement load from the database but after profiling, I have seen that all properties were loaded.
As a sample, the Contact entity contains one NotMapped property as follows.
public class Contact
{
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}
public class SampleContext : DbContext
{
public DbSet<Contact> Contacts { get; set; }
}
In the following query, I need only ContactId and FullName, I expect only ContactId, FirstName, LastName to load in the TSQL query, but all properties are loaded.
var list = dbContext.Contacts.Select( e => new
{
e.ContactId,
e.FullName
}).ToList();
If you just want to load some columns you could:
var list = dbContext.Contacts
.Where(...)
.Select( e => new
{
e.ContactId,
LastName = e.FirstName + " " + e.LastName
})
.ToList() // hit the database
I'm actually surprised this runs at all. The whole point of NotMapped is to indicate that the column is not bound and shouldn't even be used in a Select or any other Linq expression. With EF 6 trying that would have resulted in an error. Your choices were:
A) Select the entity and use the client-side computed property as you had declared. (Essentially what your code is doing behind the scenes)
or
B) as tymtam suggested, compute the property in the anonymous type.
var list = dbContext.Contacts
.Where(...)
.Select( e => new
{
e.ContactId,
LastName = e.FirstName + " " + e.LastName
}).ToList() // hit the database
EF Core had introduced client side evaluation which was enabled by default in earlier versions but I believe disabled by default since EF Core 3... This issue smells either of that you have client side evaluation enabled, or a bug in EF Core 5 that is still reverting to a client-side evaluation for an unmapped property. Either way, I am not aware of marking a property as "client side computed" as this would only possibly work if the property was declared as an expression (rather than effectively a string.Format) so your options are either of the two above, or relying on what looks to be client side evaluation which is either something your project has configured (and potentially will bite you in the butt down the road) or a bug that may be "fixed" and stop working at some point in the future.
EFCore doesn't (can't) decompile [NotMapped] to calculate the dependencies (that's a pretty hard thing to do), it defaults back to the next best thing it can do which is load all properties so it can calculate it client side.
If you do want to be able to push this calculation to SQL you need to use an expression tree. I would suggest using a package like NeinLinq or EFCore Projectables that allows you to do this in a fairly easy way.
(there's quite a few libraries that allow this, this was just the first two i knew off the top of my head)

Why do I need to .Include() collections

I wrote a query which is pretty simple:
var locations = await _context.Locations
.Include(x => x.LocationsOfTheUsers)
.Include(x => x.Address)
.ThenInclude(x => x.County)
.Where(CalculateFilters(searchObj))
.ToListAsync(cancellationToken);
And everytime LocationsOfTheUsers were null so I decided to .Include(x => x.LocationsOfTheUsers) and I received results as expected but I'm not sure why do I have to include this collections since it's defined like this:
public class Location
{
public string Title { get; set; }
public long? RegionId { get; set; }
public Region Region { get; set; }
public long? AddressId { get; set; }
public Address Address { get; set; }
public long? CountyId { get; set; }
public County County { get; set; }
public ICollection<LocationsOfTheUsers> LocationsOfTheUsers { get; set; }
}
I thought this will be automatically included since it exist as ICollection in Location class.
So why is .Include() on LocationsOfTheUsers needed here?
Thanks guys
Cheers
In entity framework the non-virtual properties represent the columns of the tables, the virtual properties represent the relations between the tables (one-to-many, many-to-many, ...)
So your property should have been defined as:
public virtual ICollection<LocationsOfTheUsers> LocationsOfTheUsers { get; set; }
One of the slower parts of a database query is the transfer of the selected data from the database management system to your local process. Hence it is wise to limit the selected data to the values you actually plan to use.
If you have a one-to-many relation between Schools and Students, and you ask for School [10] you don't want automatically to fetch its 2000 Students.
Even if you would like to have "School [10] with all its Students" it would not be efficient to use Include to also fetch the Students. Every Student will have a foreign key SchoolId with a Value of [10]. If you would use Include you would transfer this foreign key 2000 times. What a waste!
When using entity framework always use Select to fetch data and select only the properties that you actually plan to use. Only use Include if you plan to change the included items.
This way you can separate your database table structure from the actual query. If your database structure changes, only the query changes, users of your query don't notice the internal changes.
Apart from better performance and more robustness against changes, readers of your code can more easily see what values are in their query.
Certainly don't use Include to save you some typing. Having to debug one error after future changes will take way more time than you will ever save by typeing include instead of Select
Finally: limit your data early in your process, so put the Where in front.
So your query should be:
var predicate = CalculateFilters(searchObj)
var queryLocations = dbContext.Locations
.Where(predicate)
.Select(location => new
{
// Select only the location properties that you plan to use
Id = location.Id,
Name = location.Name,
// Locations Of the users:
UserLocations = location.LocationsOfTheUsers
.Select(userLocation => new
{
// again: only the properties that you plan to use
Id = userLocation.Id,
...
// Not needed, you already know the value
// LocationId = userLocation.LocationId
})
.ToList(),
Address = new
{
Street = location.Address.Street,
PostCode = location.Addrress.PostCode,
...
County = location.Address.County.Name // if you only want one property
// or if you want more properties:
County = new
{
Name = location.Address.County.Name,
Abbr = location.Address.Count.Abbr,
...
}),
},
});
I thought this will be automatically included since it exist as ICollection in Location class.
Well, it's not automatically included, probably for performance reasons as the graph of related entities and their recursive child entities may be rather deep.
That's why you use eager loading to explicitly include the related entities that you want using the Include method.
The other option is to use lazy loading which means that the related entities are loaded as soon as you access the navigation property in your code, assuming some prerequisites are fulfilled and that the context is still around when this happens.
Please refer to the docs for more information.
I believe you are using EntityFrameworkCore. In EntityFramework (EF6), lazy loading is enabled by default, However, in EntityFrameworkCore, lazy loading related entities is handled by a separate package Microsoft.EntityFrameworkCore.Proxies.
To enable the behaviour you are seeking, install the above package and add the following code
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
}
After this, the related entities will be loaded without the Include call.

How to properly make a LINQ query with clauses based on complex calculated data

I have a pretty vast experience with LINQ to Entities and LINQ to SQL but this query is making my head burn.
I need some guidance on how to successfully create a clean LINQ to Entities query, when it has conditional clauses based on calculated columns, and when projecting the data into an object, to also use that calculated columns.
The projected results class is the following:
public class FilterClientsResult
{
public enum ClientType
{
ALL,
LIST,
VIP
}
public int ClientId { get; set; }
public string Document { get; set; }
public string Email { get; set; }
public string LastName { get; set; }
public string Name { get; set; }
public ClientType Type { get; set; }
public int Visits { get; set; }
}
Then the data comes from a primary source and 3 complimentary sources.
The primary source is the Client entity, that among all its properties, it has all the projected properties, with the exception of the last 2 (Type and Visits)
The other sources are:
Subscription, where 1 Client can have many Subscription.
ClientAccess, where 1 Subscription can have many ClientAccess.
GuestListClient, where 1 Client can have many GuestListClient.
So the ClientType Type property is set to FilterClientsResult.ClientType.ALL when that Client is related with both ClientAccess and GuestListClient entities.
It's set to FilterClientsResult.ClientType.VIP when that Client is related only to ClientAccess entities, and FilterClientsResult.ClientType.LIST when that Client is only related to GuestListClient entities.
Then the Visits property is set to the sum of ClientAccess and GuestListClient entities that the Client is related to.
So the query I need should be capable of filtering clients by FilterClientsResult.ClientType but also projecting that FilterClientsResult.ClientType.
And I also need to do filtering by a Visits range, but also projecting that Visits value.
So, what is the optimal way to build a query like that
This works best with query syntax, using the let keyword to store intermediate results as variables:
from c in Clients
let vipCount = c.Subscriptions.SelectMany(s => s.ClientAccesses).Count()
let listCount = c.GuestListClients.Count()
select new FilterClientsResult {
c.ClientId,
...
Type = vipCount > 0 ? listCount > 0 ? ClientType.ALL
: ClientType.VIP
: listCount == 0 ? 0
: ClientType.LIST,
Visits = vipCount + listCount
}
(not syntax checked)
Notice that the ClientType enum must be known to EF, otherwise you first have to project the required properties where Type is an int. Then, after an AsEnumerable(), cast the int to the enum.
Also notice that there is an indecisive value when both counts are 0.

Categories

Resources