I have more than 100 tables in data base in which 60+ table's contain column called ShortCode nvarchar(12) which represent globally unique code of that record.
Now is there any way to find that the ShortCode value eg. AST_SHIP_FIRE present in any of the table in database.
Note:ShortCode is user define.
currently I am try below code,it works but I have to code for all table.
if (entities.Table1.Any(x => x.ShortCode.Trim().ToLower() == a.ShortCode.Trim().ToLower())
{return false;}
else if(entities.Table2.Any(x => x.ShortCode.Trim().ToLower() == a.ShortCode.Trim().ToLower()))
{return false;}
else if( entities.Talble3.Any(x => x.ShortCode.Trim().ToLower() == a.ShortCode.Trim().ToLower()))
{return false;}
.
.
.
else
{
//insert code
}
I think there may be more efficient way.
Ok, maybe not very straightforward but lets do it!
First of all define an interface for ShortCode property and implement it by any entity that has it:
public interface ITableWithShortCode
{
public string ShortCode { get; set; }
}
public class Table1 : ITableWithShortCode
{
public long Id { get; set; }
public string ShortCode { get; set; }
}
public class Table2 : ITableWithShortCode
{
public long Id { get; set; }
public string ShortCode { get; set; }
}
Now using power of Reflection you can write a method like this:
public bool IsExistShortCode(string shortCode)
{
using (var context = new AppDbContext())
{
/*
find all tables that are defined in your DbContext and are implemented ITableWithShortCode like:
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table2 { get; set; }
...
*/
var properties = typeof(AppDbContext).GetProperties()
.Where(p => p.PropertyType.IsGenericType
&& typeof(ITableWithShortCode).IsAssignableFrom(p.PropertyType.GenericTypeArguments[0]));
foreach (var property in properties)
{
var contextProp = (IQueryable<ITableWithShortCode>)property.GetValue(context);
bool isExist = contextProp.Any(p => p.ShortCode == shortCode);
if (isExist)
return true;
}
return false;
}
}
Note: You can do some optimization on this code, I prefered to keep it in its simplest state to show the idea. But in production, for example you can easily cache DbContext properties on startup and use it afterward
Related
Ok this one is confusing me. I'm trying to return objects with included linked objects, but it fails when I use a dto:
class MyObject1
{
public int Id { get; set; }
[Required]
public MyObject2 Mo2 { get; set }
//Other properties
}
class MyObject2
{
public int Id { get; set; }
//Other properties
}
class MyObject3
{
public int Id { get; set; }
public int MyIntValue { get; set; }
//Other properties
}
class MyDTO
{
public MyObject1 Mo1 { get; set; }
public int MyIntValue { get; set; }
}
When I use the anonymous selector, i get the linked objects loaded:
void ThisWorks()
{
var result = await
(
from mo1 in context.MyObject1s
.Include(item => item.Mo2)
//No nav-path or foriegn key setup, so do it the old fashioned way
join mo3 in context.MyObject3s on mo1.Id equals mo3.Id into mo3s
from mo3 in mo3s.DefaultIfEmpty()
select new
{
mo1,
myIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
)
.ToListAsync();
bool success = result.Mo1.Mo2 != null;
//result.Mo1.Mo2 is not null!
}
But when I try to use the Dto, it fails:
void ThisFails()
{
var result = await
(
from mo1 in context.MyObject1s
.Include(item => item.Mo2)
//No nav-path or foriegn key setup, so do it the old fashioned way
join mo3 in context.MyObject3s on mo1.Id equals mo3.Id into mo3s
from mo3 in mo3s.DefaultIfEmpty()
select new MyDto
{
Mo1 = mo1,
MyIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
)
.ToListAsync();
bool success = result.Mo1.Mo2 != null;
//result.Mo1.Mo2 is null - Why? And how do I solve it?
}
Why does the linked object not load when I create a Dto? I'm using the query in a few different places, so I want to define it once, but I need a dto to hold the MyIntValue. Is there a way to do this?
Include has no effect on projections.
You must create a separate property to hold the child entity:
class MyDTO
{
public MyObject1 Mo1 { get; set; }
public MyObject2 Mo2 { get; set; }
public int MyIntValue { get; set; }
}
and project like this:
select new MyDto
{
Mo1 = mo1,
Mo2 = mo1.Mo2,
MyIntValue = mo3 == null ? 0 : mo3.MyIntValue
}
I would suggest to not hold entities inside your DTOs. Would be better to flatten the values, or create "child DTOs" (like Dto1 and Dto2 for each entity).
Multiple answers have led me to the following 2 solutions, but both of them do not seem to be working correctly.
What I have are 2 objects
public class DatabaseAssignment : AuditableEntity
{
public Guid Id { get; set; }
public string User_Id { get; set; }
public Guid Database_Id { get; set; }
}
public class Database : AuditableEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Server { get; set; }
public bool IsActive { get; set; }
public Guid DatabaseClientId { get; set; }
}
Now, the front-end will return all selected Database objects (as IEnumerable) for a given user. I am grabbing all current DatabaseAssignments from the database for the given user and comparing them to the databases by the Database.ID property. My goal is to find the DatabaseAssignments that I can remove from the database. However, my solutions keep returning all DatabaseAssignments to be removed.
if (databases != null)
{
var unitOfWork = new UnitOfWork(_context);
var userDatabaseAssignments = unitOfWork.DatabaseAssignments.GetAll().Where(d => d.User_Id == user.Id);
//var assignmentsToRemove = userDatabaseAssignments.Where(ud => databases.Any(d => d.Id != ud.Database_Id));
var assignmentsToRemove = userDatabaseAssignments.Select(ud => userDatabaseAssignments.FirstOrDefault()).Where(d1 => databases.All(d2 => d2.Id != d1.Database_Id));
var assignmentsToAdd = databases.Select(d => new DatabaseAssignment { User_Id = user.Id, Database_Id = d.Id }).Where(ar => assignmentsToRemove.All(a => a.Database_Id != ar.Database_Id));
if (assignmentsToRemove.Any())
{
unitOfWork.DatabaseAssignments.RemoveRange(assignmentsToRemove);
}
if (assignmentsToAdd.Any())
{
unitOfWork.DatabaseAssignments.AddRange(assignmentsToAdd);
}
unitOfWork.SaveChanges();
}
I think u are looking for an Except extension, have a look at this link
LINQ: Select where object does not contain items from list
Or other way is with contains see below Fiddler link :
https://dotnetfiddle.net/lKyI2F
I have a problem when I update a line with a foreign key. The principle idea is to update a row in the database with a generic method but I have an exception when I save modification in the data base so I try to make the state of entity os modified but not the worker.
else if (ModeButtonVMCaracteristiquesType == ModeButtonVMCaracteristiqueType.EDITIONCaracteristiqueTypeItem)
{
int idCaracteristiqueSelected = Convert.ToInt32(CaracteristiqueSelected.idCharacteristicItem);
var LineModified = (from x in ImItemsModel.imtypeitems select x.imcharacteristicsitems).ToList();
LineModified.ForEach(p => ImItemsModel.Entry(p).State = System.Data.Entity.EntityState.Modified);
var UpdateCaracteristicTypeItem = StaticGenericUpdate.UpadateRowInModel<imcharacteristicsitem>(ImItemsModel, "idCharacteristicItem", idCaracteristiqueSelected, "fk_idTypeItemIMCaracteristicsItems", fk_value, propertiesForModel, propertiesForView, this);
ImItemsModel.SaveChanges();
So I have two models:
public partial class imcharacteristicsitem
{
public imcharacteristicsitem()
{
this.imvaluesofitemscaracteristics = new HashSet<imvaluesofitemscaracteristic>();
}
public int idCharacteristicItem { get; set; }
public string characteristicItem { get; set; }
public string unitCaracteristicItem { get; set; }
public int fk_idTypeItemIMCaracteristicsItems { get; set; }
public byte[] typeValueCaracteristicItem { get; set; }
public virtual ICollection<imvaluesofitemscaracteristic> imvaluesofitemscaracteristics { get; set; }
public virtual imtypeitems imtypeitem { get; set; }
}
and:
public partial class imtypeitems
{
public imtypeitems()
{
this.imcharacteristicsitems = new HashSet<imcharacteristicsitem>();
this.imitems = new HashSet<imitem>();
}
public int idTypeItem { get; set; }
public string DesignationTypeItem { get; set; }
public byte[] SymbolTypeItem { get; set; }
public Nullable<int> MaxNumberConnectionsTypeItem { get; set; }
public virtual ICollection<imcharacteristicsitem> imcharacteristicsitems { get; set; }
public virtual ICollection<imitem> imitems { get; set; }
}
and the generic method is:
public static T UpadateRowInModel<T>(DbContext Model, string NameiD, int IdSelected, string NameFk_key ,int fk_key, IList<PropertyInfo> propertiesModel, IList<PropertyInfo> propertiesView, VMCaracteristicType vm) where T : class
{
T item = Model.Set<T>().Find(IdSelected);
foreach (var property in propertiesModel)
{
if (propertiesView.Count != 0)
{
property.SetValue(item, propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)) == null ? null :
propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)).GetValue(vm));
}
if (property.Name == NameiD)
{
property.SetValue(item, IdSelected);
}
if (property.Name == NameFk_key)
{
property.SetValue(item, null);
Model.Entry(item).Property(NameFk_key).IsModified = false;
}
}
return item;
}
EDIT :
so i realise that the probleme is the entity framework can't save because my table imtypeitems have a collection of caractéristique
public virtual ICollection<imcharacteristicsitem> imcharacteristicsitems { get; set; }
so i must delet the row that i wish update it from this table and after that i will save so i can't delet the row of collection i try like this :
var RowBeforupdate = ImItemsModel.imcharacteristicsitems.Include("imtypeitem").Single(row => row.idCharacteristicItem == idCaracteristiqueSelected);
var UpdateCaracteristicTypeItem = StaticGenericUpdate.UpadateRowInModel<imcharacteristicsitem>(ImItemsModel, "idCharacteristicItem", idCaracteristiqueSelected, "fk_idTypeItemIMCaracteristicsItems", fk_value, propertiesForModel, propertiesForView, this);
ImItemsModel.Entry(RowBeforupdate).CurrentValues.SetValues(UpdateCaracteristicTypeItem);
just a ps : i am not a expert in entity framework :(
The most likely cause for the FK null exception is that the FK entity property is processed/set in the foreach loop after the FK_ID property. So even if you change the FK_ID IsModified value to false, you're most likely later setting the imtypeitem property to null.
Also you are changing all model properties based on view properties; so if there's no particular view property you'll be setting the model property to null. This is seldom the thing you want to be doing in this scenario. Usually you want to change just the corresponding view properties and leave the other model properties unchanged.
So the foreach part of your generic method should look like this:
if (propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name)) != null)
{
property.SetValue(item, propertiesView.First(elem => elem.Name.Equals(property.Name)).GetValue(vm));
}
If you have certain properties that are part of view properties but you don't want them to be updated you can just skip them (using your Nameid and NameFk_key):
if(property.Name == NameiD || property.Name == NameFk_key)
continue;
So the final form of the generic method might look something like this:
public static T UpadateRowInModel<T>(DbContext Model, string NameiD, int IdSelected, string NameFk_key ,int fk_key, IList<PropertyInfo> propertiesModel, IList<PropertyInfo> propertiesView, VMCaracteristicType vm) where T : class
{
T item = Model.Set<T>().Find(IdSelected);
foreach (var property in propertiesModel)
{
if(property.Name == NameiD || property.Name == NameFk_key)
continue;
var viewP = propertiesView.FirstOrDefault(elem => elem.Name.Equals(property.Name));
if (viewP != null)
{
property.SetValue(item, viewP.GetValue(vm));
}
}
return item;
}
There's also a variation possible where you do a foreach on the propertiesView; also the parameters for the method can be adjusted.
On a sidenote: I'm not sure if
var LineModified = (from x in ImItemsModel.imtypeitems select x.imcharacteristicsitems).ToList();
LineModified.ForEach(p => ImItemsModel.Entry(p).State = System.Data.Entity.EntityState.Modified);
does something useful, or if it does anything. The p in lambda is an ICollection of enity types and not a separate DB context entity. Not to mention that you want to set Modified state for ALL entities of type imcharacteristicsitem. Maybe you can explain the reason for this.
I have the following query:
IQueryable<BarcodeQuery> barcodes = db.Barcodes.Select(b => new BarcodeQuery
{
id = b.id,
category_id = b.category_id,
...
checkout = b.Checkouts.Select(c => new CheckoutChild
{
id = c.id,
loanee_id = c.loanee_id,
...
})
.Where(c => c.datein == null)
.FirstOrDefault()
});
And so on. It's based on this model:
public class BarcodeQuery
{
public int id { get; set; }
public int category_id { get; set; }
...
public CheckoutChild checkout { get; set; }
public CheckoutStatus checkoutStatus { get; set; }
}
My question is about CheckoutStatus down there at the bottom. It looks like this:
public class CheckoutStatus
{
public string status { get; set; }
public int daysUntilDue { get; set; }
public int daysOverdue { get; set; }
}
All of those values are derived from information I get from the query--none of them are in the database itself. What is the best way of inserting the CheckoutStatus values into each barcode record?
I have a function that creates the CheckoutStatus values themselves, I just don't know how to get them into the barcode records.
Thanks!
If b has just be created with new, how can b.Checkouts contain something? I do not really understadn what you are trying to do.
EF is converting the lambda expression into a SQL statement. Therefore you can only use expressions that can actually be translated to SQL. Just query the barcodes from the DB and then add the missing information to the barcodes returned in a loop.
var barcodes = db.Barcodes.Select(...).ToList();
foreach (Barcode b in barcodes) {
b.Checkouts = ...
}
I'm extremely new to ASP .NET and LINQ so please forgive me for my ignorance.
I've a Region class:
public class Region
{
[Key]
public int Region_ID { get; set; }
public string Region_Name { get; set; }
}
And a Service class:
public class Service
{
[Key]
public int Service_ID { get; set; }
public string Service_Name { get; set; }
}
And a mapping class which stores the many-many mapping of service_IDs with region_IDs:
public class Mapping_ServiceToRegion
{
[Key]
public int Service_ID { get; set; }
public int Region_ID { get; set; }
}
Now I want to create an API function which outputs Region_Name based on given Service_ID. This is what I have so far in my RegionsController:
// GET api/Regions/Service_ID
[ResponseType(typeof(Region))]
public async Task<IHttpActionResult> GetRegion(int id)
{
var region_id = from sr in db.Mapping_ServiceToRegions
where sr.Service_ID == id
select sr.Region_ID;
var region = await db.Regions.Select(r =>
new Region()
{
Region_ID = r.Region_ID,
Region_Name = r.Region_Name
}).SingleOrDefaultAsync(r => r.Region_ID == region_id); //ERROR
if (region == null)
{
return NotFound();
}
return Ok(region);
}
The error I'm getting is:
Cannot convert lambda expression because it is not a delegate type.
I realize that my region_id variable will have multiple region_ids based on a service_id. How can I modify the code to account for this? Is there an IN operator that I can use to say r.Region_ID IN region_id?
And does the above code look correct otherwise?
Thanks.
You should change the SingleOrDefaultAsync() call using Contains() method like below since your region_id is of IEnumerable<T> and not a single value and so you can't perform direct equality comparison.
SingleOrDefaultAsync(r => region_id.Contains(r.Region_ID))
Ahh!!! here Region is one of EF mapped entity and you are trying to construct that and thus the error. You should either chose to select an Anonymous type (or) use a custom viewmodel/DTO object like
var region = await db.Regions.Select(r =>
new
{
Region_ID = r.Region_ID,
Region_Name = r.Region_Name
}).SingleOrDefaultAsync(r => region_id.Contains(r.Region_ID));