Entity Framework Passing Table Value in Parameter Of a Function - linq

I have a requirement, where I check a particular string value within a particular column of 2 and more than 2 table (the column name of different table is same)
and if the string is present in any one of table column it will return false.
public Boolean CheckAirCraftType(String AirCraftTypeCode, ref ExceptionEntity ExceptionEntityObject)
{
Boolean InUse = false;
try
{
var QueryTFLTORD = (from tflord in RoyalFleetEntities.TFLTORDHs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select tflord).ToList();
var QueryTAIRCRFT = (from taircraft in RoyalFleetEntities.TAIRCRFTs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select taircraft).ToList();
var queryTFLTORDH = (from tfltordh in RoyalFleetEntities.TFLTORDHs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select tfltordh).ToList();
if (QueryTFLTORD.Count > 0 || QueryTAIRCRFT.Count > 0 || queryTFLTORDH.Count > 0)
{
InUse = true;
}
}
catch (DbEntityValidationException ExceptionObject)
{
..
}
return InUse;
}
It is working well, but I want to customized my code so that it can be reusable.
So I want to pass table name [in my case "TFLTORDHs",TAIRCRFTs] in the parameter of a function, and it will check whether the string is present in that table or not?
How can I achieve it? Please assist me.

Well, first of all, this is not going to be the answer you wanted.
You may create an interface, and then ask for the implementations of it.
public interface IAirCraftUseCheck
{
bool IsAirCraftUsed(string airCraftCode);
}
public class RoyalFleetEntities : IAirCraftUseCheck
{
bool IsAirCraftUsed(string airCraftCode)
{
bool InUse = false;
try
{
var QueryTFLTORD = (from tflord in RoyalFleetEntities.TFLTORDHs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select tflord).ToList();
var QueryTAIRCRFT = (from taircraft in RoyalFleetEntities.TAIRCRFTs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select taircraft).ToList();
var queryTFLTORDH = (from tfltordh in RoyalFleetEntities.TFLTORDHs.Where(a => a.ACFT_TYPE_CODE == AirCraftTypeCode)
select tfltordh).ToList();
if (QueryTFLTORD.Count > 0 || QueryTAIRCRFT.Count > 0 || queryTFLTORDH.Count > 0)
{
InUse = true;
}
}
catch (DbEntityValidationException ExceptionObject)
{
..
}
return InUse;
}
}
You can use Reflection or some libraries like StructureMap to go through all the classes that implement that interface, and then invoke the method and check the result if it is in use.
Why go this way, because in the future some other module that you are unaware of may use the Aircraft and it can even use a completely different database but still depend on the same aircraft object that you are controlling now. And if they implement that interface then you still know that it is in use or not.

Related

Linq to Entities Where Or clause

Have read other responses to similar issuebut I can not use PredicateBuilder, or copy its source. I'm trying what I've read here:
<https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
but as I'm newb, am having trouble with translating what I'm reading to what I'm applying. I have created a L2E query, and trying to append a series of OR clauses onto the WHERE:
So as simplified snippet (this one will be AND'd with the previously already defined WHERE clause):
if (firstParm == "realtor")
query = query.Where(x=> x.A == "realtor");
Now trying to OR:
if (secondParm == "clown")
// how to add this one as an OR to the above query:
query = query.OR(x=> x.fool == "clown");
I understand this can be done also with Union, but not clear on the syntax:
query = query.Union(x=> x.fool == "clown"); // ??
I've also referenced:
Combining two expressions (Expression<Func<T, bool>>)
Unable to create a compound Expression<Func<string, bool>> from a set of expressions
but again, I am new to LINQ and especially Expression Trees, so need more fillin.
There are two ways to generate expressions.
Use the compiler to do it.
Expression<Func<Person, bool>> = p => p.LastName.Contains("A");
Limitations: The only expressions that can be generated this way are instances of LambdaExpression. Also, it is rather complicated to extract parts of the expression and combine with other parts.
Use the static methods at System.Linq.Expressions.Expression.
In order to generate dynamic expressions, you can either choose between different compiler-generated expressions:
// using Record and Records as a placeholder for the actual record type and DbSet property
Expression<Func<Record,bool>> expr;
if (firstParam == "realtor") {
if (secondParam == "clown") {
expr = x => x.A == "realtor" || x.fool == "clown";
} else {
expr = x => x.A == "realtor";
}
} else {
if (secondParam == "clown") {
expr = x => x.fool="clown";
} else {
expr = x => false;
}
}
var ctx = new MyDbContext();
var qry = ctx.Records.Where(expr).Select(x => new {x.A, x.fool});
Or, you can dynamically create the expression using the static methods:
(Add using System.Linq.Expressions; and using static System.Linq.Expressions.Expression; to the top of the file.)
Expression expr;
var parameter = Parameter(typeof(Record));
if (firstParam == "realtor") {
expr = Equals(
MakeMemberAccess(parameter, typeof(Record).GetProperty("A")),
Constant("realtor")
);
}
if (secondParam == "clown") {
var exprClown = Equals(
MakeMemberAccess(parameter, typeof(Record).GetProperty("fool")),
Constant("clown")
);
if (expr == null) {
expr = exprClown;
} else {
expr = Or(expr, exprClown);
}
}
var lambda = Lambda<Func<Record,bool>>(expr, new [] {parameter});
var ctx = new MyDbContext();
var qry = ctx.Records.Where(lambda).Select(x => new {x.A, x.fool});
Given a query with a type unknown at compile time, so any variable referring to it must be IQueryable only, and not IQueryable<T>:
IQueryable qry = ctx.GetQuery(); //dynamically built query here
var parameter = Parameter(qry.ElementType);
if (firstParam == "realtor") {
expr = Equals(
MakeMemberAccess(parameter, qry.ElementType.GetProperty("A")),
Constant("realtor")
);
}
if (secondParam == "clown") {
var exprClown = Equals(
MakeMemberAccess(parameter, qry.ElementType.GetProperty("fool")),
Constant("clown")
);
if (expr == null) {
expr = exprClown;
} else {
expr = Or(expr, exprClown);
}
}
var lambda = Lambda(expr, new [] {parameter});
//Since we don't have access to the TSource type to be used by the Where method, we have
//to invoke Where using reflection.
//There are two overloads of Queryable.Where; we need the one where the generic argument
//is Expression<Func<TSource,bool>>, not Expression<Func<TSource,int,bool>>
var miWhere = typeof(Queryable).GetMethods().Single(mi => {
mi.Name == "Where" &&
mi.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2
});
qry = miWhere.Invoke(null, new [] {qry, lambda});
For Or you can try
if (secondParm == "clown")
{
query = query.Where(x=> x.fool == "clown" || x.fool==x.fool);
}
OR
if (secondParm == "clown")
{
query = query.Where(x=> x.fool == "clown" || true );
}

How to Search through all fields in a LINQ table?

in LINQ how do i search all fields in a table, what do i put for ANYFIELD in the below?
Thanks
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where d."ANYFIELD" == "VALUE" select d;
You can't. You must compare each field individually. It doesn't make sense to compare all fields, given a field may not even be of the same type as the object you're comparing to.
You can, using reflection. Try this:
static bool CheckAllFields<TInput, TValue>(TInput input, TValue value, bool alsoCheckProperties)
{
Type t = typeof(TInput);
foreach (FieldInfo info in t.GetFields().Where(x => x.FieldType == typeof(TValue)))
{
if (!info.GetValue(input).Equals(value))
{
return false;
}
}
if (alsoCheckProperties)
{
foreach (PropertyInfo info in t.GetProperties().Where(x => x.PropertyType == typeof(TValue)))
{
if (!info.GetValue(input, null).Equals(value))
{
return false;
}
}
}
return true;
}
And your LINQ query:
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where CheckAllFields(d, "VALUE", true) select d;
The third parameter should be true if you want to check all fields and all properties, and false if you want to check only all fields.
EDIT: Someone already built this...see here.
Not a full answer, but I don't agree with assertion that you simply can't...
You could come up with an extension method that dynamically filtered the IQueryable/IEnumerable (I'm guessing IQueryable by the db variable) based on properties of a similar type for you. Here's something whipped up in Linqpad. It references PredicateBuilder and is by no means complete/fully accurate, but I tested it out in Linq-to-SQL on some of my tables and it worked as described.
void Main()
{
YourDbSet.WhereAllPropertiesOfSimilarTypeAreEqual("A String")
.Count()
.Dump();
}
public static class EntityHelperMethods
{
public static IQueryable<TEntity> WhereAllPropertiesOfSimilarTypeAreEqual<TEntity, TProperty>(this IQueryable<TEntity> query, TProperty value)
{
var param = Expression.Parameter(typeof(TEntity));
var predicate = PredicateBuilder.True<TEntity>();
foreach (var fieldName in GetEntityFieldsToCompareTo<TEntity, TProperty>())
{
var predicateToAdd = Expression.Lambda<Func<TEntity, bool>>(
Expression.Equal(
Expression.PropertyOrField(param, fieldName),
Expression.Constant(value)), param);
predicate = predicate.And(predicateToAdd);
}
return query.Where(predicate);
}
// TODO: You'll need to find out what fields are actually ones you would want to compare on.
// This might involve stripping out properties marked with [NotMapped] attributes, for
// for example.
private static IEnumerable<string> GetEntityFieldsToCompareTo<TEntity, TProperty>()
{
Type entityType = typeof(TEntity);
Type propertyType = typeof(TProperty);
var fields = entityType.GetFields()
.Where (f => f.FieldType == propertyType)
.Select (f => f.Name);
var properties = entityType.GetProperties()
.Where (p => p.PropertyType == propertyType)
.Select (p => p.Name);
return fields.Concat(properties);
}
}
Useful resources for the unresolved part:
Finding the relevant properties
if this help some one.
first find all properties within Customer class with same type as query:
var stringProperties = typeof(Customer).GetProperties().Where(prop =>
prop.PropertyType == query.GetType());
then find all customers from context that has at least one property with value equal to query:
context.Customer.Where(customer =>
stringProperties.Any(prop =>
prop.GetValue(customer, null) == query));

How to create a list of child IDs

In my controller I have a method that receives a decimal value (id).
The objective of this method is to recover a list of old revisions from a database table containing work permits. Each record on this table has a WorkPermitID as a primary key and OldRevisionWorkPermitID referencing the ID of the previous version.
I have no problems when collecting the children IDs (old versions), but it raises an exception indicating that LINQ to Entities does not recognize .ToString() method.
What I'm doing wrong? I know that I need to do without converting to string (WorkPermitID is defined as numeric in the database), but I tried several ways with no success.
public ActionResult GetVersions(decimal id){
var model = new PermisosTrabajoModel();
List<string> ChildIDs = new List<string>();
var WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == id);
while (WP.OldRevisionWorkPermitID != null)
{
var child = WP.OldRevisionWorkPermitID;
ChildIDs.Add(child.ToString());
WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == child);
}
model.WPs = OtWeb.WorkPermit
.Where(q => q.DeptID == 1
&& ChildIDs.Contains(q.WorkPermitID.ToString())).ToList();
return View (model);
}
Solution1
If both of your fields are decimal... Don't use ToString(), and use a list of decimal
var model = new PermisosTrabajoModel();
var childIDs = new List<decimal>();
var WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == id);
while (WP.OldRevisionWorkPermitID != null)
{
childIDs.Add(WP.OldRevisionWorkPermitID);
WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == child);
}
model.WPs = OtWeb.WorkPermit
.Where(q => q.DeptID == 1
&& childIDs.Contains(q.WorkPermitID)).ToList();
Solution2
In linq2entities, you can use SqlFunctions.StringConvert instead of ToString() for a numeric value.
SqlFunctions.StringConvert(q.WorkPermitId)
instead of
q.WorkPermitID.ToString()
for example

Deep LINQ projections, how?

Let's say I have a model created with EF 4.0
User
Roles
Permissions
Each entity has a DeleteDate property.
I want to get a specific user (with Name =...) and have the tree filled with items where DeletedDate == null..
This must be done with anonymous type projection as result, but I don't know how to accomplish this with a hierachy deeper than 2..
This is what I already have:
public MyProjection MyCall(string givenName)
{
var result = from s in context.Users
where (s.Name == givenName &&
s.DeletedDate == null)
select new
{
s,
roles = from r in s.Roles
where r.DeletedDate == null
select r
};
var outcome = result.FirstOrDefault();
if (outcome != null)
{
var myProjection = new MyProjection()
{
User = outcome.s,
Roles = outcome.roles
};
return myProjection;
}
return null;
}
Depending on your structure you could do something like this:
var result = m.Users.Where(u => u.DeletedDate == null)
.Select( u => new
{
u,
roles = u.Roles.Where(r => r.DeletedDate == null)
.Select(r => new
{
r,
permissions = r.Permissions.Where(p => p.DeletedDate == null)
})
}).FirstOrDefault(item => item.u.Name == givenName);
If you retrieve with the following:
var result = from s in MyUsers
where s.DeletedDate == null
select new aUser{
Roles = (from r in s.Roles
where r.DeletedDate == null
select r).ToList()
};
And then create a TreeView:
TreeView treeView = new TreeView();
Then set the ItemsSource of the TreeView to the IEnumerable:
treeView.ItemsSource = result;
Then build a HierarchicalDataTemplate in your TreeView to represent your Lists (similar to this or for more in depth this), then voila!

How to get out of repetitive if statements?

While looking though some code of the project I'm working on, I've come across a pretty hefty method which does
the following:
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
if (data != null)
{
if (data.A == null)
{
data.A = fieldName;
_dataRepository.InsertOrUpdate(data);
return "A";
}
if (data.B == null)
{
data.B = fieldName;
_dataRepository.InsertOrUpdate(data);
return "B";
}
// keep going data.C through data.Z doing the exact same code
}
}
Obviously having 26 if statements just to determine if a property is null and then to update that property and do a database call is
probably very naive in implementation. What would be a better way of doing this unit of work?
Thankfully C# is able to inspect and assign class members dynamically, so one option would be to create a map list and iterate over that.
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
List<string> props = new List<string>();
props.Add("A");
props.Add("B");
props.Add("C");
if (data != null)
{
Type t = typeof(data).GetType();
foreach (String entry in props) {
PropertyInfo pi = t.GetProperty(entry);
if (pi.GetValue(data) == null) {
pi.SetValue(data, fieldName);
_dataRepository.InsertOrUpdate(data);
return entry;
}
}
}
}
You could just loop through all the character from 'A' to 'Z'. It gets difficult because you want to access an attribute of your 'data' object with the corresponding name, but that should (as far as I know) be possible through the C# reflection functionality.
While you get rid of the consecutive if-statements this still won't make your code nice :P
there is a fancy linq solution for your problem using reflection:
but as it was said before: your datastructure is not very well thought through
public String DataField(int id, string fieldName)
{
var data = new { Z = "test", B="asd"};
Type p = data.GetType();
var value = (from System.Reflection.PropertyInfo fi
in p.GetProperties().OrderBy((fi) => fi.Name)
where fi.Name.Length == 1 && fi.GetValue(data, null) != null
select fi.Name).FirstOrDefault();
return value;
}
ta taaaaaaaaa
like that you get the property but the update is not yet done.
var data = _dataRepository.Find(id);
If possible, you should use another DataType without those 26 properties. That new DataType should have 1 property and the Find method should return an instance of that new DataType; then, you could get rid of the 26 if in a more natural way.
To return "A", "B" ... "Z", you could use this:
return (char)65; //In this example this si an "A"
And work with some transformation from data.Value to a number between 65 and 90 (A to Z).
Since you always set the lowest alphabet field first and return, you can use an additional field in your class that tracks the first available field. For example, this can be an integer lowest_alphabet_unset and you'd update it whenever you set data.{X}:
Init:
lowest_alphabet_unset = 0;
In DataField:
lowest_alphabet_unset ++;
switch (lowest_alphabet_unset) {
case 1:
/* A is free */
/* do something */
return 'A';
[...]
case 7:
/* A through F taken */
data.G = fieldName;
_dataRepository.InsertOrUpdate(data);
return 'G';
[...]
}
N.B. -- do not use, if data is object rather that structure.
what comes to my mind is that, if A-Z are all same type, then you could theoretically access memory directly to check for non null values.
start = &data;
for (i = 0; i < 26; i++){
if ((typeof_elem) *(start + sizeof(elem)*i) != null){
*(start + sizeof(elem)*i) = fieldName;
return (char) (65 + i);
}
}
not tested but to give an idea ;)

Resources