Distinct not working in entity framework - c#

function for get list of documents name only with distinct...
public static List<DocumentTypeModel> GetUploadedDocumentsName(int TicketId)
{
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).Distinct().ToList();
}
return documents;
}
currently result is this -
Affidavit in Case of Cancelled Will/No Will
Affidavit in Case of Cancelled Will/No Will
Allotment Letter
Allotment Letter
Death Certificate
Death Certificate
Lease Deed
Lease Deed
Photo Identity of Applicant
Photo Identity of Applicant
Possession Letter
Possession Letter
Registered/Unregistered Will
Registered/Unregistered Will

You can use groupby and select first option like this:
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList();
documents = documents.GroupBy(x => x.DocumentTypeNameEnglish).Select(g => g.First());
}

Distinct() doesn't work like you tried on objects. Use IComparer to get this working https://support.microsoft.com/en-us/kb/320727
Create a comparer class
public class DocumentTypeModelComparer: IComparer
{
int IComparer.Compare(object a, object b)
{
if(a.Id == b.ID)
return 0;
else
return 1;
}
}
Now in your lambda expression
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList().Distinct(new DocumentTypeModelComparer()).ToList();

You are selecting the documenttypemodel and this is the distinct part (so all fields are checked), you probably want the distinct by via https://github.com/morelinq/MoreLINQ, or you can use group by with first see(linq distinct or group by multiple properties).
The other option is to select only the DocumentTypeNameEnglish field and you will get the unique documents.
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new { documentTypes =s.tbl_MstDocumentType.DocumentTypeNameEnglish}).Distinct().ToList();
Hopefully this is what you want, if not can you post more details?

https://social.msdn.microsoft.com/Forums/en-US/6303da53-c412-4ce6-a983-bd6bd87f516b/how-to-do-a-select-distinct-with-ef?forum=adodotnetentityframework
Kindly refer this link Its useful to you

Switch to the below per Vladimir's comment:
.ToList().Distinct();

Related

How to use Linq to query a table dependent on where a user belongs to another table

I have a simple issue that's running me around, I would like to find out how I can use linq to query a subset of data, e.g. I have a table that contains certificates, certificates belong to a company and a company has users that belong to it and the view is basically supposed to only display certificates for a company whereby the current user is linked to. This is what I currently have and battling with the correct syntax for an exist statement or subquery?
public List<CertificateListItemModel> GetUserCertificates()
{
var certificates = (from p in _db.Certificates
**where(
from bu2 in _db.BusinessUsers
where p.BusinessId == bu2.BusinessId && bu2.Email == _user.Name
//select new {}
)**
select new CertificateListItemModel
{
...
})
.Distinct().ToList();
return certificates;
}
This should return you a distinct list of certificates that belong to the company _user is assigned to (assuming that _user.Name and businessUser.Email really have the same content if its the same user).
var certificates = _db.Certificates
.Join(_db.Businesses,
certificate => certificate.BusinessId,
business => business.Id,
(certificate, business) => new { certificate, business })
.Join(_db.BusinessUsers.Where(user => user.Email = _user.Name),
certificateAndBusiness => certificateAndBusiness.business.Id,
businessUser => businessUser.BusinessId,
(certificateAndBusiness, businessUser) => certificate)
.GroupBy(certificate => certificate.Id)
.Select(certificates => certificates.First())
.Select(certificate => new CertificateListItemModel() {...})
.ToList()
```
I managed to resolve my issue with a simpler way and it seems it was not that difficult. The above solution confused me and I failed to implement it. Please find the simpler solution below. I just need to add the Where with a bool condition
var applications = (_db.Certificates
.Join(_db.BillingItems, p => p.CertificateId, bi => bi.CertificateId, (p, bi) => new {p, bi})
.Where(#t => (_db.BusinessUsers.Any(c => c.CbrBusinessId == #t.p.CbrOwnerRef && c.Email == _user.Name)))
.Select(#t => new CertificateListItemModel
{
CertificateId = #t.p.CertificateId,
ApplicationRefNo = #t.p.ApplicationReferenceNo,
ApplicationStatus = #t.p.ApplicationStatus,
SubmittedDateTime = #t.p.SubmittedDateTime,
IssuingLocation = #t.p.DesiredIssueLocation,
BillingId = #t.bi.BillingId,
PaperNo = #t.bi.PaperNo,
InvoiceNo = #t.bi.InvoiceNo,
BillingStatus = #t.bi.BillingStatus,
InvoiceRefNo = #t.bi.PaperNo,
BillingParty = #t.bi.BillingParty
}))
.Distinct().ToList();
return applications;

Order by Descending with multiple comparisons

I want to order the result with multiple comparisons like (by paid users, updated date, created date).
var order = _vrepository.Details()
.Where(od => od.Order.Id != null
&& od.PlanName.ToLower().Contains("DP".ToLower())
&& od.Order.Status == true)
.OrderByDescending(od => od.ValidityTill)
.Select(ord => ord.Order.Id.Value);
The above one I am getting the paid users.
var updatedList = _repository.GetUsers()
.Where(c => c.UpdatedDate != null
&& fresh <= c.UpdatedDate)
.Select(c => c.Id);
This second query I am getting updated users.
var UsersListByCreatedDate = _repository.GetUsers()
.Where(c => fresh <= c.CreatedDate)
.Select(c => c.Id);
The third one is for get the users by created date. Then I am selecting the Id (an Integer)
lstId = order.ToList();
lstUpdatedUsersId = updatedList ToList();
lstCreatedDatewiseUsers = UsersListByCreatedDate.ToList();
To show the ordered list I did the following code:
Func<IQueryable<User>, IOrderedQueryable<User>> orderingFunc = query =>
{
if (order.Count() > 0)
return query.OrderByDescending(rslt => lstId .Contains(rslt.Id))
.ThenByDescending(rslt => lstUpdatedUsersId .Contains(rslt.Id))
.ThenByDescending(rslt => lstCreatedDatewiseUsers.Contains(rslt.Id));
else
return query.OrderByDescending(rslt => lstUpdatedUsersId .Contains(rslt.Id))
.ThenByDescending(rslt => rslt.UpdatedDate);
};
But I am getting result as One Paid user, some Created user and the date is before 3 years like wise. I want to get the exact order is as follows
Ordered User
Updated User
Created User
Please help me to solve this issue. Hope I will get correct result.
I have tried this snipepd of code according to your
public class Program
{
public static void Main()
{
var l1= new List<int>{1,2,3};
var l2= new List<int>{4,5,6};
var l3= new List<int>{7,8,9};
var testList = new List<Test>{new Test{Id=9,Name="test1"},new Test{Id=11,Name="test1"},new Test{Id=5,Name="test1"},new Test{Id=7,Name="test1"},new Test{Id=2,Name="test1"}};
var orderedList= testList.OrderByDescending(e=> l1.Contains(e.Id)).ThenByDescending(e=> l2.Contains(e.Id)).ThenByDescending(e=> l3.Contains(e.Id));
Console.WriteLine(string.Join("\t", orderedList.Select(e=> e.Id).Cast<int>().ToArray()));
// it prompts 2 5 9 7 11
}
}
public class Test{
public int Id{get; set;}
public string Name{get; set;}
}
and it works as you expected. Maybe I haven't understood what you are trying to achieve.
Maybe the function that you are using to sort items is in the wrong branch of the if statment, check for if (order.Count() > 0)

Putting multiple values in a WHERE clause in Azure Mobile Services

I'm trying to figure out how to put multiple values into a WHERE clause; this is the kind of thing you'd use a IN clause for in SQL.
My current code:
if (Log.Count() == 1)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id)
.ToCollectionView();
}
else if (Log.Count() == 2)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id || Item.id == Log[1].i_id)
.ToCollectionView();
}
else if (Log.Count() == 3)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id || Item.id == Log[1].i_id || Item.id == Log[2].i_id)
.ToCollectionView();
}
It's pretty nasty. I can't find a way to put multiple values into that WHERE clause without a big if statement. Any ideas?
Try this instead:
items = itemTable
.Where(Item => Log.Any(logItem => logItem.i_id == Item.id))
.ToCollectionView();
Edit: (in response to the "not supported exception")
You can try this alternative to see if the backend supports it:
var ids = Log.Select(logItem => logItem.i_id).ToList();
var items = itemTable
.Where(Item => ids.Contains(Item.id))
.ToCollectionView();
items = itemTable.Where(Item => Log.Any(i => i.i_id == Item.id)).ToCollectionView();
I faced the same issue. Using Any or Contains as others have suggested gave me a Not Supported Exception. I posted on the Azure Mobile Services forum and was told that IN is not supported yet. They advised I use an extension method which worked perfectly for me. Below is the code I used.
public static class Extensions
{
public async static Task<List<T>> In<T>(this IMobileServiceTable<T> table, List<int> ids)
{
var query = new StringBuilder("$filter=(");
for (int i = 0; i < ids.Count; i++)
{
query.AppendFormat("id eq {0}", ids[i]); //don't forget to url escape and 'quote' strings
if (i < ids.Count - 1)
{
query.Append(" or ");
}
}
query.Append(")");
var list = await table.ReadAsync(query.ToString());
var items = list.Select(i => MobileServiceTableSerializer.Deserialize<T>(i)).ToList();
return items;
}
}
Your list can be populated by calling the extension method like this:
FavoriteJokesList = await jokeItemTable.In(favoriteJokeIds);
Source: http://social.msdn.microsoft.com/Forums/en-US/azuremobile/thread/b573ff6c-1f6b-4846-b44d-4678e3d26f66
Just for the record, in the newest Version of the Azure Mobile Service SDK (1.0), this works:
var ids = Log.Select(logItem => logItem.i_id).ToList();
var items = await itemTable
.Where(Item => ids.Contains(Item.id))
.ToCollectionAsync();

How to count entities properly

I have a method which has an attribute "user" and I'm trying to check if he's already in a team of the given "course"
private static bool UserIsInTeamOfCourse(Course course, User user)
{
var count = course.Teams.Count(x => x.Users.Contains(user));
if (count > 0)
{
return true;
}
return false;
}
But it doesn't work. I made a custom Equals method in my User model, but it still don't work.
[EDIT] It always counts zero entries, but there have to be at least one entry.
public override bool Equals(object obj)
{
return UserId == ((User)obj).UserId;
}
bool isUserInAnyTeam = course.Teams.Any(t => t.Users.Any(u => u.Id == user.Id));
This is LINQ to Objects because you are querying on the Teams collection in memory. So it assumes that the Teams collection is already loaded or will be lazily loaded. If it's not loaded and you don't use lazy loading you can create a database query on the collection:
In EF 4.1 with DbContext:
bool isUserInAnyTeam = dbContext.Entry(course).Collection(c => c.Teams).Query()
.Any(t => t.Users.Any(u => u.Id == user.Id));
Or in EF 4.0:
bool isUserInAnyTeam = course.Teams.CreateSourceQuery()
.Any(t => t.Users.Any(u => u.Id == user.Id));
Teams must be of type EntityCollection<Team> in the last case.
Another way is to query from scratch:
bool isUserInAnyTeamOfCourse = context.Courses.Any(
c => c.Id == course.Id && c.Teams.Any(t => t.Users.Any(u => u.Id == user.Id)));
Assuming there is a many to many relationship betweens teams and users and a user will not be part twice of the same team.
var count = (from c in context.Teams
from u in c.Users
where u.Id == 1
select c.Id).Count();
Entity framework can not translate your c# code in which you've overriden equals to a sql function.
Instead of comparing custom objects compare userID (which is probably int or other simple type)
private static bool UserIsInTeamOfCourse(Course course, User user)
{
return course.Teams.Where(team => team.Users.Any(u => u.userID == user.userID)).Count() > 0;
}

What would be Linq for Following

Following is the case for which I intend to write my LINQ query, but it does not work:
List <Clients> has client info and in this list there is List<JobCards>, which represents the list of job cards of that person. The job card list has one attribute named Status. I need to return all the active job cards in all Clients List.
Can it be done in LINQ?
Other code may be as follows:
BindingList<JobCard> activeJobs = new List<JobCards>();
foreach(var client in allClientList)
{
foreach(var jobCard in client.JobCards)
{
if (jobCard.Status == "Active")
{
activeJobs.Add(jobCard);
}
}
}
I am in the learning phase of LINQ. I am certain there is some error in what I've implemented, but I'm not sure how to fix it. Here is my LINQ query:
activeJobCards = new BindingList<JobCard>(
mainForm.allData.Where(
index => index.JobCards.Where(
card => card.Status == "active"
).ToList().Count > 0
).ToList()
);
What you are looking for is SelectMany
allClientList.SelectMany(c => c.JobCards).Where(jc => jc.Status == "Active");
SelectMany() will give you an IEnumerable<JobCard> and from there you select the Active job cards.
allClientList.SelectMany(c => c.JobCards.Where(jc => jc.Status == "Active"));
BindingList<JobCard> activeJobs = new List<JobCards>();
activeJobs.AddRange(allClientList.SelectMany( x=> x.JobCards)
.Where( y => y.Status == "Active"));

Categories