1

I have two in my application contexts, both are equal in schematic & Structure, one is on a remote server and the other is the local server installed on the computer. It is assumed that both databases are the same but with different data, I try to do is get all the data from both contexts for comparison and so can I have the same data in both databases. Use the Distinct extension method does not work the same. My class is called Users and their attributes are: ID, Name, Last Name, User, Password. The ID field is Identity Not null. Now I have only an identical record in both databases, therefore, to use the Distinct should not return data but I returned them. I checked the hash with the GetHashCode method and these are different. Here is my code:

    foreach (var item in remote.Users)
            lstUsers.Add(item);
    foreach (var item in local.Users)
            lstUsers.Add(item);

    var results = lstUsers.Distinct().ToList();
Richard
  • 568
  • 1
  • 6
  • 23
  • No need to compare the ID because it can be different. – Richard Jan 27 '16 at 18:39
  • I wouldn't expect this to compile... Isn't remote.Users a collection of a different type than local.Users? So how can they both be added to the same List? – GendoIkari Jan 27 '16 at 18:40
  • @GendoIkari: Presumably they are the same type, because the DB schemas are presumed identical. Each DbContext can have a separate `DbSet` as far as I know (though I have never tried it). – Eric J. Jan 27 '16 at 18:44
  • Yeah I guess you can set those mappings and settings to work that way. I've just always used the classes that EF generates; which would be within the namespace for the specific context. – GendoIkari Jan 27 '16 at 18:49
  • @GendoIkari, Both contexts are identical in schema and structure, so they can be in a single list – Richard Jan 27 '16 at 18:50

2 Answers2

0

You can create your own business object class to hold user information. Your lstUsers would be a list of this business object, instead of a list of the database / EF type. In this business object, you can override Equals and GetHashCode to compare only the information that you care about when considering if 2 user objects are the same or not.

private Business.User Transform(User user)
{
    return new Business.User()
    {
        .Username = user.Username,
        .Name = user.Name
    }; //Etc; copy all fields you care about into your business object.
}

foreach (var item in remote.Users)
        lstUsers.Add(this.Transform(item));
foreach (var item in local.Users)
        lstUsers.Add(this.Transform(item));

var results = lstUsers.Distinct().ToList();
GendoIkari
  • 11,734
  • 6
  • 62
  • 104
  • The example is a single table with a few records but I have to do the same for tables with many more fields and records, does this affect performance much? – Richard Jan 27 '16 at 18:54
  • It shouldn't have any noticeable impact on performance at all. It WILL have a pretty big impact on development time; as you're creating a whole new layer to separate your business from your database. But with that comes other advantages such as more separation of concerns; and the ability the build your business logic and core application without being dependent upon your data store. – GendoIkari Jan 27 '16 at 19:01
  • and how it works the example set? and how the new Business object is created? – Richard Jan 27 '16 at 19:25
  • @richard The code in my answer shows that. The new object is created in the private Transform method. – GendoIkari Jan 27 '16 at 19:26
  • @richard If you mean the class definition, that is written manually. You make a class to look like whatever your business needs are (which may or may not be the same as what the database looks like). – GendoIkari Jan 27 '16 at 19:27
  • then each use an object that will be transformed to use it without the ID field? – Richard Jan 27 '16 at 19:33
  • You can have the ID field or not; depending on your needs (though if the business objects should be considered the same no matter what database they came from, you probably wouldn't have an ID). You just would override Equals() and GetHashCode() to only include the fields you care about for equality. – GendoIkari Jan 27 '16 at 19:34
  • not really need that field in the code as I need to compare the information to know what synchronize data in both databases, I do not need that in both databases, that field is identity – Richard Jan 27 '16 at 19:38
0

You cannot use the default implementation of GetHashCode() to tell if two objects have the same field values. If they are different object instances (which they are), GetHashCode() will return different values for each object.

In any event, since each database has an ID that is Identity NOT NULL, the ID could be different for objects that are otherwise identical.

There are a few options, some of which may be better or weaker depending on your exact needs

  • Use a UNIQUEID (GUID) instead of integer ID, and use that for the comparison.
  • Add a unique identifier separate from the ID to each record, and use that for the comparison.
  • Implement IEquatable.

I would be cautious about overriding GetHashCode() and Equals().

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • There will be some form of omitting the field ID when making comparisons without this affecting performance? – Richard Jan 27 '16 at 18:52
  • You cannot use the auto increment ID for comparison. The ID starts as 1 and increments from there, separately in each database. Let's say user Able is added to the remote database, user Baker is added to the local database, then you try to sync. Able and Baker will both have the ID 1. Using a GUID to uniquely identify a record (either as the key or as a separate field (probably with a unique index) will be fast enough for many purposes. – Eric J. Jan 27 '16 at 19:25
  • and how to use the GUID in my code? Y need to modify the data base? – Richard Jan 27 '16 at 19:30
  • Yes, the GUID would have to be part of the database for that option. – Eric J. Jan 27 '16 at 19:31
  • how to change that field to work without problems in my code? – Richard Jan 27 '16 at 19:34