Merge two Lists of same type with diff values and avoid duplicates - c#

I have two lists of same type with different key value pairs,
List1 has "isPermanent = true" and List2 has false value and also
List1 has an extra key "nextVacationDate".
Im trying to do union of these as below but im afraid I will still get the duplicates because of different values. I need to merge both lists in to one list and order by List1 first (Permanent employees first)..is there a better way to do this using LINQ?
public newList1 List1(string abcd)
{
var result = serviceMethod1(abcd);
var newList1 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = true,
nextVacationDate =x.VacDt,
salary = x.Bsalary
}));
return newList1;
}
public newList2 List2(string defg)
{
var result = serviceMethod2(defg);
var newList2 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = false,
salary = x.Bsalary
}));
return newList2;
}
private List<emp> EmployyeList(List<emp> newList1, List<emp> newList2)
{
var sortedEmpList1 = newList1.OrderBy(i => i.Fname);
var sortedEmpList2 = newList2.OrderBy(i => i.Fname);
List<MeterModel> combinedList = newList1.Union(newList2) as List<emp>;
return combinedList;
}

You can filter the 2nd list to avoid duplicates:
newList1.Union(newList2.Where(emp2 => !newList1.Any(emp1 => emp1.employeeId == emp2.employeeId)))

Related

Entity Framework Core - Get multiple rows from one table as one DTO with multiple properties

Is it possible to select two rows into one anonymous object DTO with two properties?
With a model like:
public class Document
{
public int Id { get; set; }
public string Text { get; set; }
// Other properties
}
I am writing a method that finds the difference between two versions of a document:
public Task<string> CompareVersions(int initialId, int finalId)
So I need to retrieve the text of exactly two Documents by Id, and I need know which was which.
Currently I am constructing a Dictionary<int, string> by doing:
var dto = await _context.Documents
.Where(doc => doc.Id == initialId
|| doc.Id == finalId)
.ToDictionaryAsync(x => x.Id, x => x.Text);
and then calling dto[initialId] to get the text. However, this feels very cumbersome. Is there any way to take the two Ids and select them into one DTO in the form
{
InitialText,
FinalText
}
You have to use SelectMany
var query =
from initial in _context.Documents
where initial.Id = initialId
from final in _context.Documents
where final.Id = finalId
select new
{
InitialText = initial.Text,
FinalText = final.Text
};
var result = await query.FirstOrDefaultAsync();
Aggregate can do it too
var dto = (await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId).ToListAsync())
.Aggregate(
new { InitialText = "", FinalText = "" },
(seed, doc) => {
if(doc.Id == initialId)
seed.InitialText = doc.Text;
else
seed.FinalText = doc.Text;
}
);
I'm not sure I like it any more than I do your dictionary approach, but with an actual dto at the end rather than the dictionary:
var d = await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId)
.ToDictionaryAsync(x => x.Id, x => x.Text);
var dto = new { InitialText = d[initialId], FinalText = d[finalId] };
You could also perhaps just:
var dto = new {
InitialText = await context.Documents
.FindAsync(initialId),
FinalText = await context.Documents
.FindAsync(finalId)
};

Not Returning properly

I was trying to get employee list which not already available in another list. but im getting only first element from array list.
ex : if i try EmployeeId = new int[2] {5, 2}; the list excluding only '5'. So please help me correct my below code.
public JsonResult GetEmployees(int[] EmployeeId)
{
var dbs = new dbContext();
if (EmployeeId != null)
{
foreach (var emp in EmployeeId)
{
var EmpList = dbs.Employees.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
}).Where(o => o.EmployeeId != emp);
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
}
return null
}
Try this :
var employeeList = dbs.Employees.
.Where(e => EmployeeId.All(x=> x != e.EmployeeId))
.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
});
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
Have you tried stepping through your code?
Your foreach iterates over your EmployeeId array.
Since you have a return statement in your foreach it exits the function at that point and it only uses the first element of your array.
You need something like this:
public JsonResult GetEmployees(int[] EmployeeId)
{
var dbs = new dbContext();
if (EmployeeId != null)
{
var EmpList = dbs.Employees.Where(EmployeeId.Contains(e.EmployeeId))
.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
}).Where(o => o.EmployeeId != emp);
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
return null;
}

LINQ not sorting List<> properly

My EF query is supposed to be sorting by the date of the first Product in the list, but for some reason, it only sorts most of the products and some of the dates are in the wrong order.
Here's the code...
using (var context = new SalesEntities())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
return lst;
}
Code seems good to me, but look at how one of the dates is out of order...
weird sorting http://www.84sales.com/weird_sort.png
Try doing the order by on the inital select
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID,
c.s84_Customer.CustomerName,
c.SubdivisionID,
c.s84_Subdivision.SubdivisionName,
c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).OrderBy(x => x.CustomerExpectedDate).ToList()
});
The problem is the .First() function, witch returns the first record, but not necessarly in date order. if you wich to order your grouped datas by date so that the First() function returns the most recent date, you'll need to order your datas before grouping them, and then REorder your results with the First()function :
using (var context = PrimaryConnection.returnNewConnection())
{
var groupedData = context.s84_Schedule.AsExpandable()
.Where(predicate)
.GroupBy(c => new { c.CustomerID, c.s84_Customer.CustomerName, c.SubdivisionID, c.s84_Subdivision.SubdivisionName, c.LotNumber })
.Select(grouped => new s84_Report_Project_POCO
{
CustomerID = grouped.Key.CustomerID,
CustomerName = grouped.Key.CustomerName,
SubdivisionID = grouped.Key.SubdivisionID,
SubdivisionName = grouped.Key.SubdivisionName,
LotNumber = grouped.Key.LotNumber,
Products = grouped
.Select(x => new s84_Report_Project_Product
{
ProductID = x.ProductID,
ProductName = x.s84_Product.ProductName,
ProductDate = x.CustomerExpectedDate,
FieldRepID = x.FieldRepID,
FieldRepName = x.s84_FieldRep.FieldRepName,
InstallerID = x.InstallerID,
InstallerName = x.s84_Installer.InstallerName,
StatusID = x.StatusID,
StatusColor = x.s84_Status.StatusColor,
StatusName = x.s84_Status.StatusName,
Completed = x.Completed
}).Orderby(t => t.CustomerExpectedDate).ToList()
});
var finalList = groupedData.ToList().Where(x => x.Products.Last().Completed == false).ToList();
List<s84_Report_Project_POCO> lst = finalList.OrderBy(x => x.Products.First().ProductDate).ToList();
All SQL queries (and hence Linq queries, when attached to a SQL database) have a random order, unless you sort them.
Products is not sorted - hence it has a random order.
You sort by Products.First(), but Products has a random order, so your sort will also be random.
Make sure Products is sorted within the query, and you should be ok.
Products = grouped.Select(....)
.OrderBy(x => x.ProductDate)
.ToList()

replacement for roundtrip serialize-deserialize

I've a table with over 100 column (including blobs) and I want to make a copy of object only with a few filled columns.
right now I'm doing it by selecting needed columns and doing a round-trip serialize and deserialize with Json.NET which is not efficient. what's the best way to handle this scenario?
BL.Case mCase;
BL.Case temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
mCase = Newtonsoft.Json.JsonConvert.DeserializeObject<BL.Case>(Newtonsoft.Json.JsonConvert.SerializeObject(temp));
Use AutoMapper.
Do something like this:
BL.Case mCase = null;
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
if (temp != null)
{
mCase = Mapper.DynamicMap<BL.Case>(temp);
}
Another solution that requires a bit more code (but might perform better) is to do the following:
In case you need a single item:
BL.Case mCase = null;
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
if (temp != null)
{
mCase = new Case()
{
CaseID = temp.CaseID,
FirstName = temp.FirstName,
LastName = temp.LastName,
};
}
If you need multiple items:
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}); //Here you can filter your query if you want using Where
var result = temp
.ToList() //This will actually execute the query on the database
.Select(x => new Case() //Now you can do this since now we are working on in-memory data
{
CaseID = x.CaseID,
FirstName = x.FirstName,
LastName = x.LastName
});

advanced projection query

Any better way of doing this
using (var db = new SmartContext())
{
var MyQuery = from idr in db.ID_SB
join tk in db.Track_SB on idr.MB_Track_ID equals tk.MB_TrackID
join talr in db.Track_Album_Reln on tk.MB_TrackID equals talr.MB_Track_ID
join tal in db.Album_SB on talr.MB_AlbumID equals tal.MB_Release_ID
orderby idr.Last_played descending
select new
{
mb = tk.MB_TrackID,
Hash = idr.Hash,
Title = tk.Title,
Album = tal.Album_Name,
Times_Played = idr.Times_played,
Last_Played = idr.Last_played
};
string artist = "";
var list = new[] { new { Hash = "", Title = "", Album = "", Artist = "", Times_Played = "", Last_Played = ""}}.ToList();
list.Clear();
foreach (var q in MyQuery)
{
int i = 0;
var art = db.Track_Artist_Reln.Where(a => a.MB_Track_ID == q.mb);
foreach (var a in art)
{
var tart = db.Artist_SB.Where(ar => ar.MB_Artist_ID == a.MB_ArtistID).Select(ar => ar.Artist_Name);
foreach (var tar in tart)
{ if (i != 0) { artist = artist + ", " + tar; } else { artist = tar; i++; } }
}
list.Add(new
{
Hash = q.Hash.ToString(),
Title = q.Title.ToString(),
Album = q.Album.ToString(),
Artist = artist.ToString(),
Times_Played = q.Times_Played.ToString(),
Last_Played = q.Last_Played.ToString(),
});
}
ListView1.ItemsSource = list;
}
is there any better way for this as it is consuming lot of time
this code serves the purpose
in this i want to retrieve
hash
Title
Albumname
Artist ( containing all the artist for that song in single row field artist)
Times played
Last played
everything i am able to get just by getting join of everything apart from artist name
there are many to may relations
main tables ID_SB, Track_SB, Album_SB, Artist_SB
other are relationship storing the primary keys of both tables
The inner loop can be replaced with using string.Join(…) and .SelectMany() to flatten the nested list (really IEnumerable) into one:
var artist = string.Join(", ",
db.Track_Artist_Reln
.Where(a => a.MB_Track_ID == q.mb)
.SelectMany(a => db.Artist_SB
.Where(ar => ar.MB_Artist_ID == a.MB_ArtistID)
.Select(ar => ar.Artist_Name)));
Instead of converting the enumerable to a List manually you can use .ToList():
var list = MyQuery.Select(q => new{
Hash = q.Hash.ToString(),
Title = q.Title.ToString(),
Album = q.Album.ToString(),
Artist = string.Join(", ",
db.Track_Artist_Reln
.Where(a => a.MB_Track_ID == q.mb)
.SelectMany(a => db.Artist_SB
.Where(ar => ar.MB_Artist_ID == a.MB_ArtistID)
.Select(ar => ar.Artist_Name))),
Times_Played = q.Times_Played.ToString(),
Last_Played = q.Last_Played.ToString(),
}.ToList();

Categories

Resources