I have a List<imports> which is created by reading a CSV file. I have a List<table> by reading from a database table. What would be the correct way of setting up lambda expressions to:
- Find the intersection (Records to UPDATE or Records with NO ACTION)
- Find the new items in List (Records to INSERT)
- Find the items in List not in List (Records to DELETE)
Right now I am muscling my way through this like:
foreach (DTO.ImportData row in Helper.ImportTracker.ImportsValid)
{
bool isInsert = false;
bool isUpdate = false;
Model.Auto auto = null;
// Get auto(s) for this SKU + VIN + ClientID...
var autos = _dbFeed.Autoes.Where(a => a.StockNumber == row.Stock && a.VIN == row.VIN && a.ClientID == _targetClientID && a.SourceClientID == _sourceClientID).ToList();
if (autos.Count > 1) // ERROR...
{
Helper.ImportTracker.ImportsInvalid.Add(row);
continue;
}
else if (autos.Count == 1) // UPDATE...
{
auto = autos[0];
if (auto.GuaranteedSalePrice != row.GuaranteedSalePrice ||
auto.ListPrice != row.ListPrice ||
auto.Miles != row.Miles ||
auto.Active != row.Active ||
auto.MSRP != row.MSRP ||
auto.InternetPrice != row.Internet_Price ||
auto.InvoiceCost != row.Invoice ||
auto.Make != row.Make ||
auto.Model != row.Model ||
auto.Year != row.Year
)
{
Helper.ImportTracker.Updates.Add(row);
isUpdate = true;
}
else
{
isUpdate = false;
auto = null;
}
}
else // INSERT...
{
isInsert = true;
auto = new Model.Auto();
_dbFeed.Autoes.AddObject(auto);
Helper.ImportTracker.Inserts.Add(row);
}
// Fill in the data...
if (auto != null)
{
...
}
// left out for readability - this section just maps the import
// data to the table row and saves to the DB...
}
The above section handles the first 2 cases I listed at the beginning.
I am having a dickens of a time wrapping my head around the correct way to put lambdas together for this.
I realize I may have to convert all of my List<import> to List<table> so that I can compare apples to apples and that is not a problem. I am also thinking I need to write a custom comparer along the lines of:
class TableComparer : IEqualityComparer<table>
{
public bool Equals(table x, table y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) ||
Object.ReferenceEquals(y, null))
return false;
return x.SKU == y.SKU && x.VIN == y.VIN && x.ClientID == y.ClientID;
}
public int GetHashCode(table table)
{
if (Object.ReferenceEquals(table, null)) return 0;
int hashSKU = SKU == null ? 0 : SKU.GetHashCode();
int hashVIN = VIN == null ? 0 : VIN.GetHashCode();
int hashClientID = ClientID.GetHashCode();
return hashClientID ^ hashSKU ^ hashVIN;
}
}
Then I can do:
var UpdateAutos = autos.Intersect(new TableComparer(imports));
var InsertAutos = imports.Except(new TableComparer(autos));
var DeleteAutos = autos.Except(new TableComparer(imports));
And now my head is spinning! 😉
Am I on the right track?
ADDITIONAL INFO:
So far I am this far with my new code:
private void HandleAutos()
{
// convert to List<auto>...
List<Model.Auto> imports = AutoConvert.Convert(Helper.ImportTracker.ImportsValid, _targetClientID, _sourceClientID, DateTime.UtcNow, _dbFeed);
// get all DB records in List<auto>...
List<Model.Auto> current = _dbFeed.Autoes.Where(a => a.ClientID == _targetClientID && a.Active == true).ToList();
// isolate all Inserts, Updates and Deletes...
var intersect = imports.Intersect(current, new AutoIsIn()); // should be all autos with matching VIN & SKU //
var updates = intersect.Intersect(current, new AutoHasChanged()); // should be a subset of changed resords //
var inserts = imports.Except(current, new AutoIsIn()); // should be all the imports not in the DB //
var deletes = current.Except(imports, new AutoIsIn()); // should be all the DB records not in imports //
}
And my Comparer class looks like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RivWorks.FeedHandler.Library
{
class AutoIsIn : IEqualityComparer<Model.Auto>
{
public bool Equals(Model.Auto x, Model.Auto y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false;
return x.StockNumber == y.StockNumber && x.VIN == y.VIN;
}
public int GetHashCode(Model.Auto auto)
{
if (Object.ReferenceEquals(auto, null)) return 0;
int hashSKU = auto.StockNumber == null ? 0 : auto.StockNumber.GetHashCode();
int hashVIN = auto.VIN == null ? 0 : auto.VIN.GetHashCode();
return hashSKU ^ hashVIN;
}
}
class AutoHasChanged : IEqualityComparer<Model.Auto>
{
public bool Equals(Model.Auto x, Model.Auto y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false;
return (x.GuaranteedSalePrice != y.GuaranteedSalePrice
|| x.ListPrice != y.ListPrice
|| x.Miles != y.Miles
|| x.MSRP != y.MSRP
|| x.InternetPrice != y.InternetPrice
|| x.InvoiceCost != y.InvoiceCost
|| x.Make != y.Make
|| x.Model != y.Model
|| x.Year != y.Year
);
}
public int GetHashCode(Model.Auto auto)
{
if (Object.ReferenceEquals(auto, null)) return 0;
int hashMake = auto.Make == null ? 0 : auto.Make.GetHashCode();
int hashModel = auto.Model == null ? 0 : auto.Model.GetHashCode();
int hashYear = auto.Year.GetHashCode();
int hashGSP = auto.GuaranteedSalePrice.GetHashCode();
int hashLP = !auto.ListPrice.HasValue ? 0 : auto.ListPrice.GetHashCode();
int hashMiles = !auto.Miles.HasValue ? 0 : auto.Miles.GetHashCode();
int hashMSRP = !auto.MSRP.HasValue ? 0 : auto.MSRP.GetHashCode();
int hashIP = !auto.InternetPrice.HasValue ? 0 : auto.InternetPrice.GetHashCode();
int hashIC = !auto.InvoiceCost.HasValue ? 0 : auto.InvoiceCost.GetHashCode();
return hashMake ^ hashModel ^ hashYear ^ hashGSP ^ hashLP ^ hashMiles ^ hashMSRP ^ hashIP ^ hashIC;
}
}
}
Anything amiss so far?
-kb
Not a solution to OPs problem but in response to OPs comments…
Edit: Added Missing ParameterRebinder
The above allows you to Have…
I’ve explicitly typed the above for clarity. It’s not required.
Apologies for being in VB – I’ve got the code to hand and don’t have time to translate right now