not catch DbUpdateConcurrencyException? - entity-framework

i set a break point at var c = context.SaveChanges() , then update sql update [Student] set Name ='456' where PriKey =1 in Sqlserver Management Studio, continue, somstimes the program can not catch DbUpdateConcurrencyException, why happen this situation?
public class OfficeContext : DbContext
{
public DbSet<Student> Students { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
#"Data Source=192.168.31.215;User ID=hj;Password=hj123;Database=office;Integrated Security=false");
optionsBuilder.LogTo(Console.WriteLine);
}
[Table("Student")]
public class Student
{
[Column("PriKey")]
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Timestamp]
[Column("VerCol")]
public virtual byte[] RowVersion { get; set; }
[Column("Name")]
public string Name { get; set; }
}
}
class Program
{
static void Main(string[] args)
{
using (var context = new OfficeContext()){
try
{
var a = context.Students.FirstOrDefault(x => x.Id == 1);
a.Name = "123";
var c = context.SaveChanges();
}
catch(DbUpdateConcurrencyException e)
{
Console.WriteLine(e.Message);
}
}
}
}

Related

Asp .net core web api Entity Framework 5.0 Lazy loading

i have the following client model that has a relation with orders and BloodType tables:
public partial class Client
{
public Client()
{
ClientOrders = new HashSet<ClientOrder>();
}
public long ClientId { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public long BloodTypeId { get; set; }
public virtual BloodType BloodType { get; set; }
public virtual ICollection<ClientOrder> ClientOrders { get; set; }
}
when i try the following code to lazy load the orders and the BloodType it's not rendering them and it return the as empty list and null value.
here's my code:
[HttpGet]
[Route("clients-orders")]
public async Task<IActionResult> GetClientsOrders()
{
try
{
var result = await _trainingContext.Clients.FromSqlRaw("Exec getClients").ToListAsync();
var clientsOrders = new List<Client>();
foreach (var client in result)
{
Client currentClient = new Client()
{
ClientId = client.ClientId,
BloodTypeId = client.BloodTypeId,
PhoneNumber = client.PhoneNumber,
ClientOrders = client.ClientOrders,
BloodType = client.BloodType
};
clientsOrders.Add(currentClient);
}
return Ok(clientsOrders);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
Any solution would be very appreciated,
Thank you!

Entity Framework Core PostgreSQL json query

Always return empty results
var collection = await _context.Settings
.Select(s => new
{
s.SettingId,
s.SettingParentId,
SettingValue = s.SettingValue.GetProperty(lang)
})
.Where(s => EF.Functions.JsonExists(s.SettingValue, lang))
.ToListAsync();
I try return only key from json but always return empty, when remove "select" works fine but i need only one key
This is the model
public class Setting
{
public string SettingId { get; set; }
public string SettingParentId { get; set; }
public JsonElement SettingValue { get; set; }
}
I think you're looking for something like the following:
class Program
{
static async Task Main(string[] args)
{
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
var lang = "es";
var collection = await ctx.Settings
.Where(s => EF.Functions.JsonExists(s.SettingValue, lang))
.Select(s => new
{
s.SettingId,
s.SettingParentId,
SettingValue = s.SettingValue.GetProperty(lang).GetString()
})
.ToListAsync();
foreach (var i in collection)
{
Console.WriteLine($"{i.SettingId}: {i.SettingValue}");
}
}
}
public class BlogContext : DbContext
{
public DbSet<Setting> Settings { get; set; }
static ILoggerFactory ContextLoggerFactory
=> LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql(#"Host=localhost;Username=test;Password=test")
.EnableSensitiveDataLogging()
.UseLoggerFactory(ContextLoggerFactory);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Setting>().HasData(new Setting
{
SettingId = "1",
SettingValue = JsonDocument.Parse(#"{ ""es"" : ""valor""}").RootElement
});
}
}
public class Setting
{
public string SettingId { get; set; }
public string SettingParentId { get; set; }
public JsonElement SettingValue { get; set; }
}

I can't create a simple dataBase in EntityFramework Core

I'm a realy newbie in EntityFramework and Core.
I want to create a simple DataBase in EntityFramework Core 2.0. The project is a ConsoleApplication that I included it a Microsoft.AspNetCore.All by Nuget package. This is a code:
namespace TestEF
{
class Program
{
static void Main(string[] args)
{
string connStr = "Server=(localdb)\\mssqllocaldb;Database=SchoolDataBase;Trusted_Connection=True;MultipleActiveResultSets=true";
var db = new SchoolContext(SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connStr).Options);
db.Students.Add(
new Student()
{
LastName = "Miranda",
EnrollmentDate = DateTime.Now,
FirstMidName = "Guillermo"
});
db.SaveChanges();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
}
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions options) : base(options)
{
}
public DbSet<Student> Students { get; set; }
}
}
I'm loggin into a intranet as username "gmiranda". When I run the project I get the following message error:
System.Data.SqlClient.SqlException occurred
HResult=0x80131904
Message=Cannot open database "SchoolDataBase" requested by the login. The login failed.
Login failed for user 'domain\gmiranda'.
What is I doing wrong ?
Thanks !
You should try this code:
class Program
{
static void Main(string[] args)
{
string connStr = "Data Source=(localdb)\\mssqllocaldb;Database=SchoolDataBase;Trusted_Connection=True;MultipleActiveResultSets=true";
var db = new SchoolContext();
db.Students.Add(
new Student()
{
LastName = "Miranda",
EnrollmentDate = DateTime.Now,
FirstMidName = "Guillermo"
});
db.SaveChanges();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
}
public class SchoolContext : DbContext
{
public SchoolContext() : base()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=SchoolDataBase;Trusted_Connection=True;MultipleActiveResultSets=true");
}
public DbSet<Student> Students { get; set; }
}
Then open Package Manager Console and use command Add-Migration FirstMigrarion.
Its add migration to your database with name FirsMigration.
Then use command Update-Database.
Then run your program.
Try use this tutorial: https://learn.microsoft.com/en-us/ef/core/get-started/full-dotnet/new-db

Entity Framework one to one relation, disconnected entities

I want to work with disconnected objects. In my model a user can have or not an address.
First my model:
public class ApplicationUser : IdentityUser, IUser
{
public ApplicationUser() : base()
{
}
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual DateTime BornDate { get; set; }
public virtual SubscriptionSetting SubscriptionSetting { get; set; }
public virtual Address Address { get; private set; }
public void AddAddress(Address address)
{
this.Address = address;
}
}
public class Address
{
public Address(string id, string number, string type, string nom, string postalCode, string city, GPSCoordinates gps)
{
this.Id = id;
this.Number = number;
this.Type = type;
this.Nom = nom;
this.PostalCode = postalCode;
this.City = city;
this.GPSCoordinates = gps;
}
public virtual string Id { get; set; }
public virtual string Number { get; set; }
public virtual string Type { get; set; }
public virtual string Nom { get; set; }
public virtual string PostalCode { get; set; }
public virtual string City { get; set; }
public virtual GPSCoordinates GPSCoordinates { get; set; }
}
My context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection")
{
this.Database.Log = Console.Write;
}
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new SubscriptionSettingConfiguration());
modelBuilder.Configurations.Add(new ApplicationUserConfiguration());
modelBuilder.Configurations.Add(new AddressConfiguration());
base.OnModelCreating(modelBuilder);
}
}
My configuration:
public class ApplicationUserConfiguration : EntityTypeConfiguration<ApplicationUser>
{
public ApplicationUserConfiguration() : base()
{
HasRequired(u => u.Address).WithRequiredPrincipal();
Property(u => u.BornDate).HasColumnType("datetime2");
}
}
public class AddressConfiguration : EntityTypeConfiguration<Address>
{
public AddressConfiguration()
{
Property(m => m.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
HasKey(m => m.Id);
}
}
And my repo:
public virtual async Task<TEntity> InsertAsync(TEntity entity)
{
DbSet.Add(entity);
try
{
await _dbContext.SaveChangesAsync();
}
catch (DbEntityValidationException ex)
{
var sb = new StringBuilder();
foreach (var failure in ex.EntityValidationErrors)
{
sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
foreach (var error in failure.ValidationErrors)
{
sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
sb.AppendLine();
}
}
throw new DbEntityValidationException(
"Entity Validation Failed - errors follow:\n" +
sb.ToString(), ex
);
}
return entity;
}
Finally my unit test :
public class adress_repository_test
{
IRepository<Address> _addressRepository;
DbContext _context;
public adress_repository_test()
{
_context = new ApplicationDbContext();
_addressRepository = new Repository<Address>(_context);
}
[Fact]
public async Task insert_new_address_success()
{
GPSCoordinates gps = new GPSCoordinates(44.5, 41.2);
Address address = new Address("d0ead995-ca31-4950-bfd3-93e0ca82e37e", "BATC", "Allée", "beethoven", "60100", "creil", gps);
var result = await _addressRepository.InsertAsync(address);
Assert.NotEmpty(address.Id);
}
When the test run it throws an exception :
Violation of PRIMARY KEY constraint 'PK_dbo.Address'. Cannot insert
duplicate key in object 'dbo.Address'. The duplicate key value is
(d0ead995-ca31-4950-bfd3-93e0ca82e37e)
Sorry for this question but i haven't becareful about the config of my test, the connexion string is not present, and it's create a new database .
Steve is right the row is present in the BDD

Generic Repository EF 5 - Update Entity And It's Complex/Scalar/Navigation Properties

I'm trying to find an easy solution for updating an entity + the included properties in my solution. I've created an Generic Repository for my DBContext (database). It does update the parent entity, but not handling changes on the child properties. Is there a way to handle or track those changes?
Example code for updating child propery: (look at comment - example code)
[HttpPut]
public HttpResponseMessage PutBrand(Brand brand)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
try
{
// example code
brand.BrandSizes.FirstOrDefault().Name = "I'm a Test";
// add values
brand.State = State.Changed;
brand.DateChanged = DateTime.Now;
// update
brand = _brandService.UpdateBrand(brand);
// save
_brandService.SaveBrandChanges();
// signalR
Hub.Clients.All.UpdateBrand(brand);
return Request.CreateResponse<Brand>(HttpStatusCode.OK, brand);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
}
}
Context:
public class ERPContext : DbContext
{
#region Catalog
public DbSet<Brand> Brands { get; set; }
public DbSet<BrandSize> BrandSizes { get; set; }
public DbSet<BrandSizeOption> BrandSizeOptions { get; set; }
public DbSet<BrandTierPrice> BrandTierPrices { get; set; }
#endregion Catalog
public ERPContext()
: base("db-erp")
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Generic Repository:
public class ERPRepository<T> : IRepository<T> where T : class
{
#region Fields
private DbSet<T> _dbSet;
private DbContext _dataContext;
#endregion Fields
#region Ctor
public ERPRepository(DbContext dataContext)
{
if (dataContext == null)
{
throw new ArgumentNullException("dataContext", "dataContext cannot be null");
}
_dataContext = dataContext;
_dbSet = _dataContext.Set<T>();
}
#endregion Ctor
#region Methods
public T Add(T item)
{
return _dbSet.Add(item);
}
public T Delete(T item)
{
return _dbSet.Remove(item);
}
public T Update(T item)
{
var updated = _dbSet.Attach(item);
_dataContext.Entry(item).State = EntityState.Modified;
return updated;
}
public IQueryable<T> Query(params Expression<Func<T, object>>[] includes)
{
var query = _dbSet;
if (includes != null)
{
includes.ToList().ForEach(x => query.Include(x).Load());
}
return query;
}
public void SaveChanges()
{
_dataContext.SaveChanges();
}
#endregion Methods
}
Model:
public class Brand
{
#region Ctr
public Brand()
{
BrandSizes = new List<BrandSize>();
BrandTierPrices = new List<BrandTierPrice>();
}
#endregion Ctr
#region Properties
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? LogoId { get; set; }
public int DisplayOrder { get; set; }
public bool Deleted { get; set; }
public bool Locked { get; set; }
public State State { get; set; }
public DateTime DateChanged { get; set; }
public DateTime DateCreated { get; set; }
#endregion Properties
#region Mapping
public virtual Picture Logo { get; set; }
public virtual List<BrandSize> BrandSizes { get; set; }
public virtual List<BrandTierPrice> BrandTierPrices { get; set; }
#endregion Mapping
}
BrandService:
public partial class BrandService : IBrandService
{
#region Fields
private readonly IRepository<Brand> _brandRepository;
private readonly IRepository<BrandSize> _brandSizeRepository;
private readonly IRepository<BrandSizeOption> _brandSizeOptionRepository;
#endregion Fields
#region Ctor
public BrandService(IRepository<Brand> brandRepository, IRepository<BrandSize> brandSizeRepository, IRepository<BrandSizeOption> brandSizeOptionRepository)
{
_brandRepository = brandRepository;
_brandSizeRepository = brandSizeRepository;
_brandSizeOptionRepository = brandSizeOptionRepository;
}
#endregion Ctor
#region Methods
public virtual IEnumerable<Brand> GetAllBrands()
{
return _brandRepository.Query(x => x.BrandSizes);
//return _brandRepository.Query();
}
public virtual Brand GetBrandById(int id)
{
return _brandRepository.Query().Where(x => x.Id == id).FirstOrDefault();
}
public virtual Brand InsertBrand(Brand brand)
{
return _brandRepository.Add(brand);
}
public virtual Brand UpdateBrand(Brand brand)
{
return _brandRepository.Update(brand);
}
public virtual Brand DeleteBrand(Brand brand)
{
return _brandRepository.Delete(brand);
}
public virtual void SaveBrandChanges()
{
_brandRepository.SaveChanges();
}
#endregion Methods
}
Create IObjectWithState interface and State enum to track changes manually:
public interface IObjectWithState
{
State State { get; set; }
}
public enum State
{
Added,
Unchanged,
Modified,
Deleted
}
and implement the interface in every mapped entity
public class Brand:IObjectWithState
{ ....
[NotMapped]
public State State { get; set; }}
and add these two helper methods to convert the state and to apply the changes in the entire graph:
public static EntityState ConvertState(State state)
{
switch (state)
{
case State.Added :
return EntityState.Added;
case State.Deleted:
return EntityState.Deleted;
case State.Modified:
return EntityState.Modified;
case State.Unchanged:
return EntityState.Unchanged;
default:
return EntityState.Unchanged;
}
}
public static void ApplyStateChanges(this DbContext context)
{
foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = StateHelpers.ConvertState(stateInfo.State);
}
}
and when update or insert any object edit the state of it like this object.State = State.Modified;
and then modify your insert or update method to be like this:
public void InsertOrUpdate(T entity, bool IsGraph)
{
if (((IObjectWithState)entity).State == State.Added)
{
dataContext.Entry(entity).State = System.Data.Entity.EntityState.Added;
}
else
{
dbset.Add(entity);
dataContext.Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
//This method change the state of every changed object
if (IsGraph)
ApplyStateChanges(dataContext);
dataContext.Commit();
}