Mam więc na przykład ten obiekt:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public List<Car> Cars { get; set; }
public List<User> Children { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
}
Czy jest więc sposób na zaktualizowanie obiektu User
, zaktualizowanie go Children
i Cars
? Jeśli w obiekcie do aktualizacji nie ma samochodu, który jest w nowym obiekcie, dodaj go, ale jeśli w obiekcie do aktualizacji jest i nie ma go w nowym obiekcie, usuń go z obiektu do aktualizacji, i zaktualizuj wszystkie atrybuty wszystkich dopasowanych samochodów, a także właściwości Children
.
Czy to możliwe?
3 odpowiedzi
Tak! Możliwe, tutaj rozwiązanie (to rozwiązanie aktualizuje wszystkie właściwości, właściwości klasy i właściwości kolekcji, ale jeśli w środku znajduje się klasa, klasa musi dziedziczyć po Abstrakcyjnej Entity):
private void UpdateAllProperties<idType, entityType>(entityType currentEntity, entityType newEntity)
where idType : IEquatable<idType>
where entityType : AbstractEntity<idType>
{
var currentEntityProperties = currentEntity.GetType().GetProperties();
var newEntityProperties = newEntity.GetType().GetProperties();
foreach (var currentEntityProperty in currentEntityProperties)
{
foreach (var newEntityProperty in newEntityProperties)
{
if (newEntityProperty.Name == currentEntityProperty.Name)
{
if (currentEntityProperty.PropertyType.BaseType.IsGenericType &&
currentEntityProperty.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(AbstractEntity<>))
{
var idPropertyType = currentEntityProperty.PropertyType.GetProperty("Id").PropertyType;
var entityPropertyType = currentEntityProperty.PropertyType;
this.InvokeUpdateAllProperties(currentEntityProperty.GetValue(currentEntity, null),
newEntityProperty.GetValue(newEntity, null),
idPropertyType, entityPropertyType);
break;
}
else if (currentEntityProperty.PropertyType.GetInterfaces().Any(
x => x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(ICollection<>)))
{
dynamic currentCollection = currentEntityProperty.GetValue(currentEntity, null);
dynamic newCollection = newEntityProperty.GetValue(newEntity, null);
this.UpdateCollectionItems(currentEntityProperty, currentCollection, newCollection);
dynamic itemsToRemove = Enumerable.ToList(Enumerable.Except(currentCollection, newCollection));
dynamic itemsToAdd = Enumerable.ToList(Enumerable.Except(newCollection, currentCollection));
dynamic itemsAreEqual = Enumerable.ToList(Enumerable.Intersect(currentCollection, newCollection));
for (int i = 0; i < itemsToRemove.Count; i++)
{
currentCollection.Remove(Enumerable.ElementAt(itemsToRemove, i));
}
for (int i = 0; i < itemsToAdd.Count; i++)
{
currentCollection.Add(Enumerable.ElementAt(itemsToAdd, i));
}
break;
}
else
{
currentEntityProperty.SetValue(currentEntity, newEntityProperty.GetValue(newEntity, null), null);
break;
}
}
}
}
}
private void UpdateCollectionItems(PropertyInfo currentEntityProperty, dynamic currentCollection, dynamic newCollection)
{
var collectionType = currentEntityProperty.PropertyType.GetInterfaces().Where(
x => x.IsGenericType &&
x.GetGenericTypeDefinition() == typeof(ICollection<>)).First();
var argumentType = collectionType.GetGenericArguments()[0];
if (argumentType.BaseType.IsGenericType &&
argumentType.BaseType.GetGenericTypeDefinition() == typeof(AbstractEntity<>))
{
foreach (var currentItem in currentCollection)
{
foreach (var newItem in newCollection)
{
if (currentItem.Equals(newItem))
{
var idPropertyType = currentItem.GetType().GetProperty("Id").PropertyType;
var entityPropertyType = currentItem.GetType();
this.InvokeUpdateAllProperties(currentItem, newItem, idPropertyType, entityPropertyType);
}
}
}
}
}
private void InvokeUpdateAllProperties(dynamic currentEntity, dynamic newEntity, dynamic idPropertyType, dynamic entityPropertyType)
{
var method = this.GetType().GetMethod("UpdateAllProperties", BindingFlags.Instance | BindingFlags.NonPublic);
var genericMethod = method.MakeGenericMethod(idPropertyType, entityPropertyType);
genericMethod.Invoke(this, new[] { currentEntity, newEntity });
}
Przykład zastosowania:
Abstrakcyjny podmiot:
public abstract class AbstractEntity<idType>
where idType : IEquatable<idType>
{
public idType Id { get; set; }
}
Przykładowe zajęcia:
public class User : AbstractEntity<int>
{
public string Name { get; set; }
public List<Car> OtherCars { get; set; }
public Car MainCar { get; set; }
public bool Equals(Car other)
{
if (this.Id == other.Id)
{
return true;
}
else
{
return false;
}
}
}
public class Car : AbstractEntity<int>
{
public string Name { get; set; }
public string Color { get; set; }
public bool Equals(Car other)
{
if (this.Id == other.Id)
{
return true;
}
else
{
return false;
}
}
}
Korzystanie z metody:
User currentUser = new User()
{
Id = 1,
Name = "Vinicius",
OtherCars = new List<Car>()
{
new Car()
{
Id = 2,
Name = "Corsa II",
Color = "Azul"
},
new Car()
{
Id = 3,
Name = "Palio",
Color = "Vermelho"
},
new Car()
{
Id = 4,
Name = "Fusca",
Color = "Azul"
}
},
MainCar = new Car()
{
Id = 1,
Name = "Corsa",
Color = "Preto"
}
};
User updatedUser = new User()
{
Id = 1,
Name = "Vinicius Ottoni",
OtherCars = new List<Car>()
{
new Car()
{
Id = 5,
Name = "Voyage",
Color = "Azul"
},
new Car()
{
Id = 6,
Name = "Voyage II",
Color = "Vermelho"
},
new Car()
{
Id = 4,
Name = "Fusca",
Color = "Rosa"
}
},
MainCar = new Car()
{
Id = 2,
Name = "Voyage",
Color = "Vinho"
}
};
this.UpdateAllProperties<int, User>(currentUser, updatedUser);
Aby znaleźć dodane i usunięte:
var removedCars = orgUser.Cars.Except(changedUser.Cars);
var addedCars = changedUser.Cars.Except(orgUser.Cars);
Użyj przeciążenia funkcji porównującej równość, aby znaleźć wszystkie zmienione samochody: http://msdn.microsoft. com/en-us/library/bb336390.aspx
Zrób to samo dla dzieci.
Najprostszym sposobem byłoby ustawienie właściwości Cars
i Children
w obiekcie docelowym tak, aby odnosiły się do list Cars
i Children
w obiekcie źródłowym.
originalUser.Cars = changedUser.Cars;
originalUser.Children = changedUser.Children;
Może to nie być możliwe, jeśli obiekty zostały utworzone w różnych kontekstach ORM.
Alternatywą jest porównanie list i odpowiednia modyfikacja obiektów. musisz napisać metodę, aby to zrobić. LINQ byłby bardzo pomocny.
Aktualizuj
Oto szybka i brudna (i prawdopodobnie BARDZO nieefektywna) metoda rozszerzenia, która może być przydatna:
public void UpdateUser(this User user, User changedUser)
{
var changedUserCarIDs = changedUser.Cars.Select(c => c.Id).ToArray();
user.Cars = user.Cars.Where(c => changedUserCarIDs.Contains(c.Id)).ToList();
foreach (var changedCar in changedUser.Cars)
{
var car = user.Cars.SingleOrDefault(c => c.Id == changedCar.Id);
if (car == null) user.Cars.Add(car = new Car());
car.Name = changedCar.Name;
car.Color = changedCar.Color;
}
}
Podobne pytania
Powiązane pytania
Nowe pytania
c#
C # (wymawiane „patrz ostro”) jest językiem programowania wysokiego poziomu, statycznie typowanym, wieloparadygmatowym opracowanym przez firmę Microsoft. Kod C # zwykle jest przeznaczony dla rodziny narzędzi Microsoft .NET i czasów wykonywania, do których należą między innymi .NET Framework, .NET Core i Xamarin. Użyj tego tagu w przypadku pytań dotyczących kodu napisanego w C # lub C # formalnej specyfikacji.