default values in LINQ query - asp.net

I have following Linq query/function in my MVC3 application.
public AuditTrail GetNamesAddressesEmployers(long registryId , int changedField) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress;
}
I want that if otherNameAndAddress = null then its properties should be assigned some values.
otherNameAndAddress has Name and description property. This GetNamesAddressesEmployers is being used at 3 places. I want to assign different values to name and description when otherNameAndAddress = null at all three locations.

You're already using FirstOrDefault() so why not specify the Default:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField)
{
return context.AuditTrails
.Where(a => a.ChangedField == changedField
&& a.RegistryId == registryId)
.DefaultIfEmpty(new AuditTrail { /* fill properties here */ })
.FirstOrDefault();
}

Well, you could change the return statement to:
return otherNameAndAddress ?? new AuditTrail { Name = "Default",
Description = "Default };
or something like that... but you say you want to assign different default values for different calls. That means you'll either need to pass the default in, or perform the defaulting (e.g. in the same way, via the null-coalescing operator) at the call site.
For example:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField,
AuditField defaultValue) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress && defaultValue;
}
or keep it as it currently is, and use this at the call site:
var auditTrail = GetNamesAddressesEmployers(registryId, changedField) ??
new AuditTrail { Name = "Foo", Description = "Bar" };
It's not really clear which is best based on your description.
EDIT: As mentioned by Justin, you could use DefaultIfEmpty instead (just before FirstOrDefault). That means you have to pass the value in rather than doing it at the call site, but other than that they're very similar solutions.

Related

nullable int in linq query [duplicate]

I have a Category entity which has a Nullable ParentId field. When the method below is executing and the categoryId is null, the result seems null however there are categories which has null ParentId value.
What is the problem in here, what am I missing?
public IEnumerable<ICategory> GetSubCategories(long? categoryId)
{
var subCategories = this.Repository.Categories.Where(c => c.ParentId == categoryId)
.ToList().Cast<ICategory>();
return subCategories;
}
By the way, when I change the condition to (c.ParentId == null), result seems normal.
Other way:
Where object.Equals(c.ParentId, categoryId)
or
Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)
The first thing to do is to put on logging, to see what TSQL was generated; for example:
ctx.Log = Console.Out;
LINQ-to-SQL seems to treat nulls a little inconsistently (depending on literal vs value):
using(var ctx = new DataClasses2DataContext())
{
ctx.Log = Console.Out;
int? mgr = (int?)null; // redundant int? for comparison...
// 23 rows:
var bosses1 = ctx.Employees.Where(x => x.ReportsTo == (int?)null).ToList();
// 0 rows:
var bosses2 = ctx.Employees.Where(x => x.ReportsTo == mgr).ToList();
}
So all I can suggest is use the top form with nulls!
i.e.
Expression<Func<Category,bool>> predicate;
if(categoryId == null) {
predicate = c=>c.ParentId == null;
} else {
predicate = c=>c.ParentId == categoryId;
}
var subCategories = this.Repository.Categories
.Where(predicate).ToList().Cast<ICategory>();
Update - I got it working "properly" using a custom Expression:
static void Main()
{
ShowEmps(29); // 4 rows
ShowEmps(null); // 23 rows
}
static void ShowEmps(int? manager)
{
using (var ctx = new DataClasses2DataContext())
{
ctx.Log = Console.Out;
var emps = ctx.Employees.Where(x => x.ReportsTo, manager).ToList();
Console.WriteLine(emps.Count);
}
}
static IQueryable<T> Where<T, TValue>(
this IQueryable<T> source,
Expression<Func<T, TValue?>> selector,
TValue? value) where TValue : struct
{
var param = Expression.Parameter(typeof (T), "x");
var member = Expression.Invoke(selector, param);
var body = Expression.Equal(
member, Expression.Constant(value, typeof (TValue?)));
var lambda = Expression.Lambda<Func<T,bool>>(body, param);
return source.Where(lambda);
}
My guess is that it's due to a rather common attribute of DBMS's - Just because two things are both null does not mean they are equal.
To elaborate a bit, try executing these two queries:
SELECT * FROM TABLE WHERE field = NULL
SELECT * FROM TABLE WHERE field IS NULL
The reason for the "IS NULL" construct is that in the DBMS world, NULL != NULL since the meaning of NULL is that the value is undefined. Since NULL means undefined, you can't say that two null values are equal, since by definition you don't know what they are.
When you explicitly check for "field == NULL", LINQ probably converts that to "field IS NULL". But when you use a variable, I'm guessing that LINQ doesn't automatically do that conversion.
Here's an MSDN forum post with more info about this issue.
Looks like a good "cheat" is to change your lambda to look like this:
c => c.ParentId.Equals(categoryId)
You need to use operator Equals:
var subCategories = this.Repository.Categories.Where(c => c.ParentId.Equals(categoryId))
.ToList().Cast<ICategory>();
Equals fot nullable types returns true if:
The HasValue property is false, and the other parameter is null. That is, two null values are equal by definition.
The HasValue property is true, and the value returned by the Value property is equal to the other parameter.
and returns false if:
The HasValue property for the current Nullable structure is true, and the other parameter is null.
The HasValue property for the current Nullable structure is false, and the other parameter is not null.
The HasValue property for the current Nullable structure is true, and the value returned by the Value property is not equal to the other parameter.
More info here Nullable<.T>.Equals Method
Or you can simply use this. It will also translate to a nicer sql query
Where((!categoryId.hasValue && !c.ParentId.HasValue) || c.ParentId == categoryId)
What about something simpler like this?
public IEnumerable<ICategory> GetSubCategories(long? categoryId)
{
var subCategories = this.Repository.Categories.Where(c => (!categoryId.HasValue && c.ParentId == null) || c.ParentId == categoryId)
.ToList().Cast<ICategory>();
return subCategories;
}
Linq to Entities supports Null Coelescing (??) so just convert the null on the fly to a default value.
Where(c => c.ParentId == categoryId ?? 0)

Determine if a field is a system field

I would like to know if there is a clever/short way to determine if a field in a table is generated from the system. I only have the TableNum and the FieldNum as variables (nothing hard coded, only dynamic values) and I'd like to be able to write something like this (pseudo-code):
if( Sys::isSystemField(tableId, fieldId) )
{
//...
}
Instead of:
//...
str fieldName;
//...
;
//...
fieldName = dictTable.fieldName(fieldId);
if(fieldName == "modifiedDateTime"
|| fieldName == "DEL_ModifiedTime"
|| fieldName == "modifiedBy"
|| //etc...)
{
//...
Which is what I'll be writing if there is no way to do what I'm looking for. Hopefully someone can help, I haven't find anything about that in the documentation unfortunately.
Cheers
Use isSysId a global method.
It is for example used in Global::buf2buf:
static void buf2Buf(Common _from, Common _to)
{
DictTable dictTable = new DictTable(_from.TableId);
fieldId fieldId = dictTable.fieldNext(0);
while (fieldId && ! isSysId(fieldId))
{
_to.(fieldId) = _from.(fieldId);
fieldId = dictTable.fieldNext(fieldId);
}
}

Is this an inefficient way to compare data across multiple tables?

I am using the following code to first check if a string is located somewhere within a column in my database. If it is, I am then needing to check if a few additional criteria are met by looking at different parts of the database (can be seen in the code below). I am not sure if this is an efficient method for doing this or if there is a much simpler way:
(from my Controller)
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
ViewBag.code = code;
// Need to check if this code is active
var order = db.Orders.SingleOrDefault(
o => o.OrderCode == code
&& o.Active == true);
if (order == null)
{
//Invalid
}
else
{
var orderIdent = db.OrderDetails.SingleOrDefault(
p => p.OrderDetailId == order.OrderId);
var barIdent = db.Drink.SingleOrDefault(
q => q.EstablishmentsID == orderIdent.DrinksId);
var barName = db.Establishment.SingleOrDefault(
r => r.EstablishmentsId == barIdent.EstablishmentsID);
ViewBag.barId = barName.name;
ViewBag.sample = order.Email;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar != barName.name)
{
//Not a match
}
else
{
//Match
}
}
return View();
}
Is this something to worry about? Is there a more efficient way of performing the actions that I am currently performing? Should I change the first table that is referenced to include data from the table I ultimately compare it to to avoid what seems to be an inefficient way of comparing information from different tables?
You should check the SQL query that gets generated. You can do that by e.g. outputting the queries to the console, which is done by setting db.Log = Console.Out;. There should be a similar method to output to the web page in your case. The lazy nature of LINQ makes things difficult to predict.
Other than that, you could make your life much easier if you create foreign key relationships between your tables, i.e. OrderDetails has Orders.OrderId as a FK. This will allow Entity Framework to generate navigational properties for your database. With them your code would look like this:
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
var detail = db.Orders.Where(o => o.OrderCode == code && o.Active == true)
.Select(o => new {
OrderCode = o.OrderCode,
BarId = o.Drink.Establishment.Select(n => n.name),
Sample = o.Email
})
.SingleOrDefault();
if (detail != null)
{
ViewBag.code = detail.OrderCode;
ViewBag.barId = detail.BarId;
ViewBag.sample = detail.Sample;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar == detail.BarId)
{
//Match
}
else
{
//Not a match
}
}
else
{
//Invalid
}
return View();
}

Searching for a string in a single column in a table within an ASP.NET MVC application

I have a table named Orders that has a column named OrderCode that stores a string that I randomly generate at the time of creation.
I want to make sure this string (OrderCode) is unique before I save it to my table.
How I have attempted to do this:
bool isUnique = false;
var order = new Order();
var code = RandomCode.Generate();
while (isUnique == false) // checks to see if the code we generated is unique among all generated codes, if not, will generate another code
{
var activeOrders = storeDB.Orders.Find("OrderCode", code);
if (activeOrders == null)
{
isUnique = true;
}
else
{
code = RandomCode.Generate();
}
}
order.OrderCode = code;
The problem appears to be that the DbSet<TEntity>.Find Method is actually used to search through primary keys - but I am needing to search for a string that is not a primary key.
What is a correct approach to this situation?
if (context.Orders.Any(o => o.OrderCode == code))
{
// key found
}
if (context.Orders.FirstOrDefault(o => o.OrderCode == code) != null)
{
// key found
}
May I ask why you don't just use a System.Guid though (Guid.NewGuid().ToString())? This would virtually eliminate this kind of issue.

Retrieve Arguments of a Workflow (with default values)?

Given is a Workflow Foundation 4 runtime that is working against a website ;)
We need to get the arguments of workflows to show the user an editor to enter the arguments. For that we need all arguments with names, types and - default values, as well as an indication whether an argument is required.
Workflows are stored as XAML files.
How to do that? The data seems to be in the Activity Metadata which seems to be not avaialble outside the Workflow. In addition, the Workflow Engine ModelService is for the Designer and has a lot of overhead.
Any easy way to retrieve this information?
I've already done something similar. Reflection might be your best (and only) option if you want a generic approach.
// Just an holder for InArgument informations
class InArgumentInfo
{
public string InArgumentName { get; set; }
public string InArgumentDescription { get; set; }
public bool InArgumentIsRequired { get; set; }
}
static ICollection<InArgumentInfo> GetInArgumentsInfos(Activity activity)
{
var properties = activity.GetType()
.GetProperties()
.Where(p => typeof(InArgument).IsAssignableFrom(p.PropertyType))
.ToList();
var argumentsCollection = new Collection<InArgumentInfo>();
foreach (var property in properties)
{
var descAttribute = property
.GetCustomAttributes(false)
.OfType<DescriptionAttribute>()
.FirstOrDefault();
string description = descAttribute != null && !string.IsNullOrEmpty(descAttribute.Description) ?
descAttribute.Description :
string.Empty;
bool isRequired = property
.GetCustomAttributes(false)
.OfType<RequiredArgumentAttribute>()
.Any();
argumentsCollection.Add(new InArgumentInfo
{
InArgumentName = property.Name,
InArgumentDescription = description,
InArgumentIsRequired = isRequired
});
}
return argumentsCollection;
}
This way you can not only retrieve the argument's name but also other information hold by the argument's attributes. For example I choose to give argument an user-friendly name through [Description] attribute (eg. instead of MyPropertyName user sees "My Property Name").
Note: if you can ensure that you activity is an ActivityBuilder or DynamicActivity they both have Properties property that you can use, but the principle is the same.
Load it as DynamicActivity and iterate over Properties property
var dynamicActivity = ActivityXamlServices.Load(foo) as DynamicActivity
foreach(DynamicActivityProperty prop in dynamicActivity.Properties)
{
// ...
}
UPDATE: Missed default value part
foreach (var prop in dynamicActivity .Properties)
{
object defaultValue;
if (prop.Value == null)
{
defaultValue = null;
}
else
{
Type genericTypeDefinition = prop.Type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(InArgument<>) || genericTypeDefinition == typeof(InOutArgument<>))
{
var valueProp = prop.Value.GetType().GetProperty("Expression", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly);
var expression = valueProp.GetValue(prop.Value, null);
var expressionValueProp = expression.GetType().GetProperty("Value");
defaultValue = expressionValueProp.GetValue(expression, null);
}
}
}
Not totally guaranteed, there are some checks you have to do.

Resources