Indirection with linq : Change query expression "Select" according users parameters - linq

I use a table "TLanguage" to record lable results of my site. I have 4 columns in this table: French, English, German and Spanish.
In a MVC application I use this query:
var req = (from TYP in context.TYP_TypeMission
join ML in context.TLanguage on TYP.IDTMultiLanguage equals ML.IDTMultiLanguage
where TYP.IDTFiliale == idFiliale
orderby TYP.LibTypeMission
select new SelectListItem
{
Selected = TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)TYP.IdTypeMission),
Text = ML.French
}).ToList();
How can I change ML.French by ML.English or ML.German in my query according the language of my site?
Is it possible to create an indirection in the query?

It is possible to parametrize the mapping like this:
public class TLanguageMap : EntityTypeConfiguration<TLanguage>
{
public TLanguageMap(string language)
{
this.HasKey(t => t.TLanguageId);
this.Property(t => t.Translation).HasColumnName(language);
}
}
In the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TLanguageMap(this._language));
}
and its constructor:
public LocalizableContext(string language)
{
this._language = language;
}
Now when constructing a context you can determine for which language it is:
var context = new LocalizableContext("French");
And the query will always be:
...
select new SelectListItem
{
Selected = TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)TYP.IdTypeMission),
Text = ML.Translation
})
You may want to make it more robust by using an enum for the languages and a switch statement to get the database column names.

You can save the beginning of your query into variable and change only the last part later:
var query = from TYP in context.TYP_TypeMission
join ML in context.TLanguage on TYP.IDTMultiLanguage equals ML.IDTMultiLanguage
where TYP.IDTFiliale == idFiliale
orderby TYP.LibTypeMission
select new { ML, TYP };
List<SelectListItem> req;
if(Site.Lang == "DE")
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.German
}).ToList();
}
else if(Site.Lang == "FR")
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.French
}).ToList();
}
else
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.English
}).ToList();
}
Query won't be executed until ToList() is called.

Related

Load multipe sharepoint list item fields in one Go using CSOM c#

***ctx.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["Column1"],
item => item["Column2"]
));***
i have list of fields in a array of string instead of column1 and column2, how can i pass it through in include linq, not able to create proper lambda on runtime. i tried following ways but couldn't get success. Static befor loops works but thw fields added in loop fails as it doesn't evaluate string value in loop
***Expression<Func<ListItem, object>>[] paramss = new
Expression<Func<ListItem, object>>[length];
paramss[0] = x => x.ContentType;
paramss[1] = x => x["Title"];
count = 2;
foreach (string item in solConnDefModel.Columns)
{ paramss[count] = x => x[item];
count++;
}***
Please take a reference of below code:
List dlist = context.Web.Lists.GetByTitle("listname");
context.Load(dlist);
context.ExecuteQuery();
string[] fieldNames = { "Id", "Title", "num", "mStartDate" };
// Create the expression used to define the fields to be included
List<Expression<Func<ListItemCollection, object>>> fieldsToBeIncluded = new List<Expression<Func<ListItemCollection, object>>>();
foreach (string s in fieldNames)
{
fieldsToBeIncluded.Add(items => items.Include(item => item[s]));
}
// Initialize the collection of list items
var listItems = dlist.GetItems(new CamlQuery());
context.Load(listItems, fieldsToBeIncluded.ToArray());
context.ExecuteQuery();
You can hover on load method to see what type parameter it requires, then generate a corresponding one and pass it.
i have to create lambda expression at runtime. following code i was able to get expected value
Expression<Func<ListItem, object>>[] paramss = new Expression<Func<ListItem, object>>[length];
foreach (string item in Columns)
{
if (item.ToLower() != "contenttype")
{
ParameterExpression parameter = Expression.Parameter(typeof(ListItem), "x");
var propertyInfo = typeof(ListItem).GetMethod("get_Item");
var arguments = new List<Expression> { Expression.Constant(item) };
var expression = Expression.Call(parameter, propertyInfo, arguments);
var lambda = Expression.Lambda<Func<ListItem, object>>(expression, parameter);
paramss[count] = lambda;
}
else
{
paramss[count] = x => x.ContentType;
}
count++;
}

Why does my selected value not get added to my SelectListItem as the “Text” and “Value” properties do?

I am trying to set a default value of a list in a partial view. The partial view is called using this…
#Html.Action("Acton", "Controller", new { department = item.Data.departmentNumber, defaultValue="someValue" })
Then in the controller I have…
[ChildActionOnly]
public ActionResult Categories(int? id, int? department, string defaultValue)
{
var typeList = from e in db.Rubrics where e.DepartmentID == department select e;
var selectedRubrics = typeList.Select(r => r.Category);
List<String> rubricsList = selectedRubrics.ToList();
var categories = new List<SelectListItem>();
for (int i = 0; i < rubricsList.Count(); i++)
{
categories.Add(new SelectListItem
{
Text = rubricsList[i],
Value = rubricsList[i],
Selected = (defaultValue == "defaultValueGetsSentToView")
});
}
var ViewModel = new RubricsViewModel
{
Category = "Select a Category",
Categories = categories
};
return View(ViewModel);
}
Why does my selected value not get added to my SelectListItem as the “Text” and “Value” properties are? Thanks for any help!
Assuming the values in the code are the literal values you are using, "defaultValue" is "someValue" and you are setting selected with the comparison defalutValue == "defaultValueGetsSentToView".
"someValue" == "defaultValueGetsSentToView" evaluates to false.

Conversion of a LINQ query fom method syntax to query syntax

Hi I am changing career to computer programming. I am still in college. I have to change the following LINQ query from method syntax to query syntax. What gets me is the 2 steps process of the method query. First it gets a teamId and then it returns a list based on the context and using the teamId. I am confused about how to translate this to query method. Most of the questions are about going from query syntax to method.
Can someone Help?
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = context
.TeamMembers
.Include("Team")
.FirstOrDefault(c => c.UserId == userId)
.Team.Id;
return context
.TeamTemplates.Include("Template")
.Where(c => c.TeamId == teamId)
.Select(c => c.Template)
.Where(c => c.StatusId == 1/*Active*/)
.Select(k => new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
}
}
The first one is pretty straight forward. I delayed the execution of the query until the end. Since you may get a null reference exception in your example accessing .FirstOrDefault().Team.Id;
var teamId = (from c in context.TeamMembers.Include("Team")
where c.UserId == userId
select c.Team.Id).FirstOrDefault();
This one you just need to use an into in order to continue your query statement
return (from c in context.TeamTemplates.Include("Template")
where c.TeamId == teamId
select c.Template into k
where k.StatusId == 1
select new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = (from tm in context.TeamMembers.Include("Team")
where tm.UserId==userId
select tm.Id).FirstOrDefault();
IEnumerable<TemplateView> result = from k in (from tmp in context.TeamTemplates.Include("Template")
select tmp.Template)
where k.StatusId==1
select new
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
};
return result;
}

create extension method in linq

How to create an extension method to the string to get a sum
create Sumstring extension method
List<myclass> obj=new List<myclass>()
{
new myclass(){ID=1,name="ali",number=1},
new myclass(){ID=1,name="karimi",number=2},
new myclass(){ID=2,name="mohammad",number=4},
new myclass(){ID=2,name="sarbandi",number=5},
};
var query = (from p in obj
group p by p.ID into g
select new
{ id = g.Key, sum = g.Sumstring(p => p.name) }).ToList();
dataGridView1.DataSource=query;
I connect to the database
What is the code
You've not specified what SumString really returns, but looks like you're talking about string concatenation of all source collection elements.
It can be easily done using String.Join method:
public static class EnumerableOfString
{
public static string SumString<TSource>(this IEnumerable<TSource> source, Func<TSource, string> selector, string separator = null)
{
return String.Join(separator ?? string.Empty, source.Select(i => selector(i)));
}
}
That method allows following calls:
g.SumString(p => p.name)
with string.Empty as default deparator and with custom separator specified:
g.SumString(p => p.name, ",")
If all you want to do is concatenate the strings in that group you can use the built-in Aggregate function:
var query = (from p in obj
group p by p.ID into g
select new
{ id = g.Key, sum = g.Aggregate((tot, next) => tot + "," + next) }
).ToList();

EF single entity problem

I need to return a single instance of my viewmodel class from my repository in order to feed this into a strongly-typed view
In my repository, this works fine for a collection of viewmodel instances:
IEnumerable<PAWeb.Domain.Entities.Section> ISectionsRepository.GetSectionsByArea(int AreaId)
{
var _sections = from s in DataContext.Sections where s.AreaId == AreaId orderby s.Ordinal ascending select s;
return _sections.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
But when I attempt to obtain a single entity, like this:
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
I get
Error 1 Cannot implicitly convert type
'System.Linq.IQueryable<PAWeb.Domain.Entities.Section>' to
'PAWeb.Domain.Entities.Section'. An explicit conversion exists
(are you missing a cast?)"
This has got to be simple, but I'm new to c#, and I can't figure out the casting. I tried (PAWeb.Domain.Entities.Section) in various places, but no success. Can anyone help??
Your query is returning an IQueryable, which could have several items. For example, think of the difference between an Array or List of objects and a single object. It doesn't know how to convert the List to a single object, which one should it take? The first? The last?
You need to tell it specifically to only take one item.
e.g.
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
).FirstOrDefault();
}
This will either return the first item, or null if there are no items that match your query. In your case that won't happen unless the table is empty since you don't have a where clause.

Resources