I have two tables. One of them is Customers which is in the database, the other one is ChangedCustomers, which comes from the user. I make some operations on ChangedCustomers table before sending the database so I use ChangedCustomersDTO. After these operations, I can not update the database.
public async Task<int> UpdateCustomers (IENumerable<ChangedCustomersDTO> changedCustomers
{
foreach(var item in changedCustomers)
{
var customer=_context.Customers.FirstOrDefault(x => x.CustomerId == item.CustomerId);
if(customer != null)
{
customer.Id=item.Id;
customer.Name=item.Name;
customer.Address=item.Address;
}
else
{
_context.Customers.Add(new Models.Customers()
{
customer.Id=new Guid();
customer.Name=item.Name;
customer.Address=item.Address;
}
}
}
return await _context.SaveChangesAsync();
}
All the data I have at the moment will be updated customers. They entered the if(customer !=null) but the method returns 0 and is not updated.
After comments I edit my code, but again returns zero.
public async Task<int> UpdateCustomers (IENumerable<ChangedCustomersDTO> changedCustomers
{
foreach(var item in changedCustomers)
{
var customer=_context.Customers.Where(x => x.CustomerId == item.CustomerId).FirstOrDefault();
if(customer != null)
{
customer.Name=item.Name;
customer.Address=item.Address;
}
else
{
_context.Customers.Add(new Models.Customers()
{
customer.Id=new Guid();
customer.Name=item.Name;
customer.Address=item.Address;
}
}
}
return await _context.SaveChangesAsync();
}
you have several bugs in your code. try this:
var customer=_context.Customers.Where(x => x.Id == item.Id).FirstOrDefault();
if(customer != null)
{
customer.Name=item.Name;
customer.Address=item.Address;
_context.Entry(customer).State=EntityState.Modified;
}
else
{
_context.Customers.Add(new Models.Customers
{
Id=new Guid(),
Name=item.Name,
Address=item.Address
}
}
Related
public ServiceResponce Write(Guid senderID, Guid reciverID, string body)
{
Message message = new Message
{
Body = body
};
var reciver = context.Users.Where(c => c.Id == reciverID).Single();
var sender = context.Users.Where(c => c.Id == senderID).Single();
message.Sender = sender;
message.Reciver = reciver;
context.SaveChanges();
return new ServiceResponce();
}
I got exeption of empty sequence . I am geting Guid id resulsts from HTTPContext.Users.FindFirstValue(ClaimTypes.NameIdentifier)
and I am geting results it is not null.
I cant solve this problem.
Caller method :
public IActionResult Wright(Guid reciverID,string body)
{
var userID = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
var neededID = Guid.Parse(userID);
_chatService.Write(neededID, reciverID, body);
return Ok();
}
Try this:
public ServiceResponce Write(...)
{
...
var reciver = context.Users.Where(c => c.Id == reciverID).SingleOrDefault();
var sender = context.Users.Where(c => c.Id == senderID).SingleOrDefault();
if(reciver == null || sender ==null)
{
//Log??
return null;
}
...
}
public IActionResult Wright(Guid reciverID,string body)
{
var userID = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
// If you really want to put the validation logic here
Guid neededID;
if (!Guid.TryParse(userId, out var neededID))
{
//Log?
return BadRequest();
}
if(_chatService.Write(neededID, reciverID, body) == null)
return BadRequest();
return Ok();
}
I'm trying to validate an entity coming from an External context has not changed.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
I have a method which takes in an entity which has not been loaded from the context.
public bool Validate(Employee employee)
{
using (var context = new Context())
{
return context.Entry(employee).State == EntityState.Modified;
}
}
I would like to attach and verify that the attached entity is not modified from whats in the database.
I would prefer not to manually have to iterate of the properties. Is there a way to hack around this?
No need to attach the external entity. You can use the external entity to set values of the database entity and then check the state of the latter:
public bool Validate(Employee externalEmployee)
{
using var context = new Context(); // C# 8.0
var dbEntity = context.Where(x => x.Id == externalEmployee.Id).SingleOrDefault();
if (dbEntity != null)
{
context.Entry(dbEntity).CurrentValues.SetValues(externalEmployee);
return context.Entry(dbEntity).State == EntityState.Modified;
}
return false; // Or true, depending on your semantics.
}
You can try:
public static List<string> GetChanges<T>(this T obj, T dbObj)
{
List<string> result = new List<string>();
var type = typeof(T);
foreach (var prop in type.GetProperties())
{
var newValue = prop.GetValue(obj, null);
var dbValue = prop.GetValue(dbObj, null);
if(newValue == null && dbValue != null)
{
result.Add(prop.Name);
continue;
}
if (newValue != null && dbValue == null)
{
result.Add(prop.Name);
continue;
}
if (newValue == null && dbValue == null)
continue;
if (!newValue.ToString().Equals(dbValue.ToString()))
result.Add(prop.Name);
}
return result;
}
if resultList.Count > 0, your object has changes.
In your Validate Method:
public bool Validate(Employee employee)
{
using (var context = new Context())
{
Employee dbEmployee = context.Employee.Find(employee.Id);
if(employee.GetChanges(dbEmployee).Count > 0)
return true;
return false;
}
}
It's a god workaround =D
Works for me!
Updating records using EF, but it is not updating accordingly. I just want to update only the fields that are not null and modified. In previous I'm doing like this:
_context.Attach(exist).CurrentValues.SetValues(t);
which it will update all the fields and I don't want that.
Is there anything that I missed on my code?
public virtual async Task<T> UpdateAsync(T t, object key)
{
if (t == null)
return null;
T exist = await _context.Set<T>().FindAsync(key);
if (exist != null)
{
// _context.Attach(exist).CurrentValues.SetValues(t);
_context.Attach(exist);
var entry = _context.Entry(t);
Type type = typeof(T);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.GetValue(t, null) == null)
{
entry.Property(property.Name).IsModified = false;
}
}
// _context.Attach(exist).CurrentValues.SetValues(t);
await _context.SaveChangesAsync();
}
return exist;
}
I am using something like this
public virtual async Task<T> UpdateAsync(T t, object key)
{
if (t == null)
return null;
T exist = await _context.Set<T>().FindAsync(key);
if (exist != null)
{
_context.Entry(exist).CurrentValues.SetValues(t);
var result = await Context.SaveChangesAsync();
if (result == 0) return null
}
return exist;
}
So, we created this project: https://github.com/efonsecab/BlazorRestaurant
The EF Core logic for SaveChanges is extended to automatically fill the data for the auditing columns.
Logic is in the BlazorRestaurantDbContext.partial.cs file.
public partial class BlazorRestaurantDbContext
{
public override int SaveChanges()
{
ValidateAndSetDefaults();
return base.SaveChanges();
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
ValidateAndSetDefaults();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
ValidateAndSetDefaults();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
ValidateAndSetDefaults();
return base.SaveChangesAsync(cancellationToken);
}
private void ValidateAndSetDefaults()
{
//Check https://www.bricelam.net/2016/12/13/validation-in-efcore.html
var entities = from e in ChangeTracker.Entries()
where e.State == EntityState.Added
|| e.State == EntityState.Modified
select e.Entity;
string ipAddresses = String.Empty;
string assemblyFullName = String.Empty;
string rowCretionUser = String.Empty;
if (entities.Any(p => p is IOriginatorInfo))
{
ipAddresses = String.Join(",", GetCurrentHostIPv4Addresses());
assemblyFullName = System.Reflection.Assembly.GetEntryAssembly().FullName;
if (Thread.CurrentPrincipal != null && Thread.CurrentPrincipal.Identity != null)
rowCretionUser = Thread.CurrentPrincipal.Identity.Name;
else
rowCretionUser = "Unknown";
}
foreach (var entity in entities)
{
if (entity is IOriginatorInfo)
{
IOriginatorInfo entityWithOriginator = entity as IOriginatorInfo;
if (String.IsNullOrWhiteSpace(entityWithOriginator.SourceApplication))
{
entityWithOriginator.SourceApplication = assemblyFullName;
}
if (String.IsNullOrWhiteSpace(entityWithOriginator.OriginatorIpaddress))
{
entityWithOriginator.OriginatorIpaddress = ipAddresses;
}
if (entityWithOriginator.RowCreationDateTime == DateTimeOffset.MinValue)
{
entityWithOriginator.RowCreationDateTime = DateTimeOffset.UtcNow;
}
if (String.IsNullOrWhiteSpace(entityWithOriginator.RowCreationUser))
{
try
{
entityWithOriginator.RowCreationUser = rowCretionUser;
}
catch (Exception)
{
entityWithOriginator.RowCreationUser = "Unknown";
}
}
}
var validationContext = new ValidationContext(entity);
Validator.ValidateObject(
entity,
validationContext,
validateAllProperties: true);
}
}
public static List<string> GetCurrentHostIPv4Addresses()
{
//Check https://stackoverflow.com/questions/50386546/net-core-2-x-how-to-get-the-current-active-local-network-ipv4-address
// order interfaces by speed and filter out down and loopback
// take first of the remaining
var allUpInterfaces = NetworkInterface.GetAllNetworkInterfaces()
.OrderByDescending(c => c.Speed)
.Where(c => c.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
c.OperationalStatus == OperationalStatus.Up).ToList();
List<string> lstIps = new();
if (allUpInterfaces != null && allUpInterfaces.Count > 0)
{
foreach (var singleUpInterface in allUpInterfaces)
{
var props = singleUpInterface.GetIPProperties();
// get first IPV4 address assigned to this interface
var allIpV4Address = props.UnicastAddresses
.Where(c => c.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(c => c.Address)
.ToList();
allIpV4Address.ForEach((IpV4Address) =>
{
lstIps.Add(IpV4Address.ToString());
});
}
}
return lstIps;
}
}
We have used this same code in other apps and works, great.
In this specific app, however, the System.Threading.Thread.CurrentPrincipal and ClaimsPrincipal.Current, are null, when the ValidateAndSetDefaults method is executed.
Even tried the following
services.Configure<JwtBearerOptions>(
JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters.NameClaimType = "name";
options.Events.OnTokenValidated = (context) =>
{
System.Threading.Thread.CurrentPrincipal = context.Principal;
return Task.CompletedTask;
};
options.SaveToken = true;
});
The context.Principal does have all the data we need at this point, but we still get null reading the Thread's CurrenPrincipal object.
Any ideas how to fix it, so we can properly get the Authenticated User information in the code above, it exists in context.Principal, it is just not accesible later in the SaveChanges for EF Core.
Fixed by using Dependency Injection along with HttpContextAccesor
https://github.com/efonsecab/BlazorRestaurant/blob/main/src/BlazorRestaurantSln/BlazorRestaurant.DataAccess/Data/BlazorRestaurantDbContext.partial.cs
In my WPF 4.0 project, I have an ObservableCollection that contain some selected Visual3D from the view :
public ObservableCollection<Visual3D> SelectedElements
{
get { return _selectedElements; }
set
{
if (Equals(_selectedElements, value))
{
return;
}
_selectedElements = value;
RaisePropertyChanged(() => SelectedElements);
}
}
Visual3D elements are selected by clicking and the source-code in the VM is :
public HitTestResultBehavior HitTestDown(HitTestResult result)
{
var resultMesh = result as RayMeshGeometry3DHitTestResult;
if (resultMesh == null)
return HitTestResultBehavior.Continue;
// Obtain clicked ModelVisual3D.
var vis = resultMesh.VisualHit as ModelVisual3D;
if (vis != null)
{
Type visType = vis.GetType();
if (visType.Name == "TruncatedConeVisual3D" || visType.Name == "BoxVisual3D")
{
var geoModel = resultMesh.ModelHit as GeometryModel3D;
if (geoModel != null)
{
var selecteMat = geoModel.Material as DiffuseMaterial;
if (selecteMat != null) selecteMat.Brush.Opacity = selecteMat.Brush.Opacity <= 0.7 ? 1 : 0.7;
}
// Otherwise it's a chair. Get the Transform3DGroup.
var xformgrp = vis.Transform as Transform3DGroup;
// This should not happen, but play it safe anyway.
if (xformgrp == null)
{
return HitTestResultBehavior.Stop;
}
// Loop through the child tranforms.
foreach (Transform3D t in xformgrp.Children)
{
// Find the TranslateTransform3D.
var trans =
t as TranslateTransform3D;
if (trans != null)
{
// Define an animation for the transform.
var anima = new DoubleAnimation();
if (trans.OffsetY == 0)
{
DependencyProperty prop = TranslateTransform3D.OffsetZProperty;
if (Math.Abs(trans.OffsetZ) < 2)
{
anima.To = 20.5*Math.Sign(trans.OffsetZ);
Debug.Assert(SelectedElements != null, "SelectedElements != null");
}
else
{
anima.To = 1*Math.Sign(trans.OffsetZ);
SelectedElements.Add(vis);
}
// Start the animation and stop the hit-testing.
trans.BeginAnimation(prop, anima);
return HitTestResultBehavior.Stop;
}
}
}
}
}
return (HitTestResultBehavior) HitTestFilterBehavior.Continue;
}
and I want to delete one or all this Visual3D element
Thank you in advance
I have implemented this methode but it's not work :
private void UnloadProduct()
{
if (CanUnload)
{
foreach (Visual3D selectedElement in SelectedElements)
{
if (selectedElement.DependencyObjectType.Name == "TruncatedConeVisual3D")
{
var test = (TruncatedConeVisual3D) selectedElement;
int id = test.VisualId;
ElementsCollection.RemoveAt(id);
RaisePropertyChanged(() => ElementsCollection);
}
else
{
var test = (BoxVisual3D) selectedElement;
int id = test.VisualId;
ProductsCollection.RemoveAt(id);
}
}
}
}