EnumerateFiles in Linq - c#

I have LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable1[System.String] EnumerateFiles(System.String)' method, and this method cannot be translated into a store expression.` error. I need to get links to images from folders, I get ID from the database.
// Collect flat items and add in List<>
var nearestItems = from item in _db.Flats
select new listItem()
{
Price = item.Price,
Address = item.Address,
Bathroom = item.Bathroom,
BesprovodnoiInternet = item.BesprovodnoiInternet,
City = item.City,
FloorAll = item.FloorAll,
FloorCurrent = item.FloorCurrent,
Funiture = item.Funiture,
Kondicioner = item.Kondicioner,
PartyFree = item.PartyFree,
RoomQuantity = item.RoomQuantity,
TipArendy = item.TipArendy,
TV = item.TV,
ImagesString = Directory.EnumerateFiles(Server.MapPath("~/Content/Prop/" + item.FlatID + "/"))
.Select(fn => "~/Content/Prop/" + item.FlatID + "/" + Path.GetFileName(fn)).ToList()
};
Are there fix for this or alternate code?

Your LINQ query should be translated to SQL query to run on SQL Server. It is obvious that the engine cant translate Directory.EnumerateFiles to SQL query.
You can add new property FlatId to your listItem and try this:
// Collect flat items and add in List<>
var nearestItems = (from item in _db.Flats
select new listItem()
{
Price = item.Price,
Address = item.Address,
Bathroom = item.Bathroom,
BesprovodnoiInternet = item.BesprovodnoiInternet,
City = item.City,
FloorAll = item.FloorAll,
FloorCurrent = item.FloorCurrent,
Funiture = item.Funiture,
Kondicioner = item.Kondicioner,
PartyFree = item.PartyFree,
RoomQuantity = item.RoomQuantity,
TipArendy = item.TipArendy,
TV = item.TV,
FlatId = item.FlatID,
}).ToList();
foreach(var item in nearestItems)
{
item.ImagesString = Directory.EnumerateFiles(Server.MapPath("~/Content/Prop/" + item.FlatId + "/"))
.Select(fn => "~/Content/Prop/" + item.FlatId + "/" + Path.GetFileName(fn)).ToList();
}

EntityFramework will build query based on your LINQ which will execute in the database. So there are some constarints while using LINQ to Entity. How must EF convert this code to the database query? Directory.EnumerateFiles
There is no way.
So, you must select only required properties and then change them as you wish in .net:
var nearestItems = (from item in _db.Flats
select new listItem()
{
Price = item.Price,
Address = item.Address,
Bathroom = item.Bathroom,
BesprovodnoiInternet = item.BesprovodnoiInternet,
City = item.City,
FloorAll = item.FloorAll,
FloorCurrent = item.FloorCurrent,
Funiture = item.Funiture,
Kondicioner = item.Kondicioner,
PartyFree = item.PartyFree,
RoomQuantity = item.RoomQuantity,
TipArendy = item.TipArendy,
TV = item.TV,
FlatId = item.FlatID,
}).ToList();
And in you class change the get accessor of your property ImagesString:
public List<string> ImagesString
{
get
{
return Directory.EnumerateFiles(Server.MapPath("~/Content/Prop/" + FlatID + "/"))
.Select(fn => "~/Content/Prop/" + FlatID + "/" + Path.GetFileName(fn))
.ToList();
}
}

Related

Selecting from multiple lists in model and putting it in a dropdown

I am trying to populate my dropdownlist by doing this
var componentList = (from c in model.Components
select new
{
compID = c.ID,
compName = c.CompID + ":" + c.ComponentName
}).OrderBy(x => x.compName).ToList();
(from sc in model.ComponentSubComps
select new
{
compID = sc.ID,
compName = sc.SubCompID + ":" + sc.SubCompName
}).OrderBy(x => x.compName).ToList();
ViewBag.Components = new SelectList(componentList, "compID", "compName");
But it is only pulling the data from the model.Components list in the model. How can I make it so it also pulls from the model.ComponentSubComps list as well?
I don't know if you want to combine the components and sub-components or not. Combining them as a dangerous potential to mix up the IDs, assuming if they're in a separate table in your database and their primary keys are just incremental integer values.
This would become a serious bug if it's not being taken care of first. If their IDs could be the same, you might have to go with two dropdowns (one for components and one for sub-components) instead of one.
If you have to combine both of them, it sounds like you almost have to combine something uniquely with the IDs, assign them as different groups and parse the IDs when you receive from post back:
// Define the Groups
var componentGroup = new SelectListGroup { Name = "Component" };
var subComponentGroup = new SelectListGroup { Name = "SubComponent" };
var componentOptions = model.Components
.OrderBy(x => x.ComponentName)
.Select(x => new SelectListItem
{
Value = "c:" + x.CompID,
Text = x.CompID + ":" + x.ComponentName,
Group = componentGroup
});
var subComponentOptions = model.ComponentSubComps
.OrderBy(x => x.SubCompName)
.Select(x => new SelectListItem
{
Value = "sc:" + x.SubCompID,
Text = x.SubCompID + ":" + x.SubCompName,
Group = subComponentGroup
});
var dropdownOptions = new List<SelectListItem>();
dropdownOptions.AddRange(componentOptions);
dropdownOptions.AddRange(subComponentOptions);
Then when the user makes a selection and post the dropdown value back to the sever, you might have to parse the selected dropdown value and see if the ID belongs to component or sub-component.
If there is no difference between components and sub-components, then you can just combine them as easily as:
var componentOptions = model.Components
.OrderBy(x => x.ComponentName)
.Select(x => new SelectListItem
{
Value = x.CompID,
Text = x.CompID + ":" + x.ComponentName
});
var subComponentOptions = model.ComponentSubComps
.OrderBy(x => x.SubCompName)
.Select(x => new SelectListItem
{
Value = x.SubCompID,
Text = x.SubCompID + ":" + x.SubCompName
});
// This is your SelectList. I would highly recommend you build a strongly-typed
// view model and use it instead of ViewBag.
var dropdownOptions = new List<SelectListItem>();
dropdownOptions.AddRange(componentOptions);
dropdownOptions.AddRange(subComponentOptions);
You have two statements. The result from the first statement you store in componentList but the result from the second statement isn't stored anywhere.
Try to add the result from the second statement to componentList.
Probably List<T>.AddRange(IEnumerable<T>) is the best option.
Edit:
var componentList = (from c in model.Components
select new
{
compID = c.ID,
compName = c.CompID + ":" + c.ComponentName
}).OrderBy(x => x.compName).ToList();
var secondResult = (from sc in model.ComponentSubComps
select new
{
compID = sc.ID,
compName = sc.SubCompID + ":" + sc.SubCompName
}).OrderBy(x => x.compName).ToList();
componentList.AddRange(secondResult);
ViewBag.Components = new SelectList(componentList, "compID", "compName");
You can write the queries with entities and get:
var componentList = model.Components.Select(c => new Components
{
compID = c.ID,
compName = c.CompID + ":" + c.ComponentName
}).OrderBy(x => x.compName).ToList();
var componentList1 = model.ComponentSubComps.Select(c => new Components
{
compID = c.ID,
compName = c.SubCompID + ":" + c.SubCompName
}).OrderBy(x => x.compName).ToList();
componentList.AddRange(componentList1);
ViewBag.Components = new SelectList(componentList, "compID", "compName");

WIQL Query not including "System.AssignedTo" Field

I have this WIQL, who's purpose is to find the user assigned to the work item.
var wiql = string.Format("SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State]" +
" FROM WorkItems" +
" WHERE ([System.TeamProject] = '{0}')" +
" AND ([System.WorkItemType] = 'Task' OR [System.WorkItemType] = 'Bug')" +
" ORDER BY [System.Id]", projectName);
I'm executing it as so...
Wiql wiql = new Wiql() { Query = wiqlQueryString };
using (var workItemTrackingHttpClient = new WorkItemTrackingHttpClient(VstsAccess.AccessUri, VstsAccess.AccessCredentials))
{
var workItemQueryResult = workItemTrackingHttpClient.QueryByWiqlAsync(wiql).Result;
if (workItemQueryResult != null && workItemQueryResult.WorkItemRelations.Any())
{
List<int> sourceIdList = new List<int>();
foreach (var item in workItemQueryResult.WorkItemRelations)
sourceIdList.Add(item.Target.Id);
int[] arr = sourceIdList.ToArray();
string[] fields = { "System.Id", "System.WorkItemType", "System.AssignedTo", "System.Title", "System.Description", "System.State", "System.IterationPath", "System.TeamProject", "System.ChangedDate", "System.ChangedBy", "System.CreatedDate" };
return workItemTrackingHttpClient.GetWorkItemsAsync(arr, fields, workItemQueryResult.AsOf).Result;
}
else
return new List<WorkItem>();
}
But the "AssignedTo" and "Description" fields are not showing up in the work items' dictionary field-set. Why is this so and how can I fix this?
The query results will only contain fields that are non-null, i.e. nobody is assigned to the work item, the field won't be in the Fields dictionary at all.
You need to implement a custom check for those fields and assign them to something according to your logic:
int[] arr = ids.ToArray();
string[] fields = new string[] {
"System.Id",
"System.Title",
"System.State",
"System.AssignedTo"
};
var workItems = await workItemTrackingHttpClient.GetWorkItemsAsync(arr, fields, workItemQueryResult.AsOf);
List<WorkItemData> list = new List<WorkItemData>();
foreach (var workItem in workItems)
{
var wi = new WorkItemData(workItem.Id.Value);
wi.Title = workItem.Fields["System.Title"].ToString();
wi.State = workItem.Fields["System.State"].ToString();
wi.AssignedTo = workItem.Fields.ContainsKey("System.AssignedTo") ? workItem.Fields["System.AssignedTo"].ToString() : "";
list.Add(wi);
}
You could use the code below to query out workitems and it has "AssignedTo" and "Description" field values.
WorkItemStore workItemStore = teamProjectCollection.GetService<WorkItemStore>();
string queryString = string.Format("SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State]" +
" FROM WorkItems" +
" WHERE ([System.TeamProject] = '{0}')" +
" AND ([System.WorkItemType] = 'Task' OR [System.WorkItemType] = 'Bug')" +
" ORDER BY [System.Id]", "Mtt-Scrum"); ;
// Create and run the query.
Query query = new Query(workItemStore, queryString);
WorkItemCollection witCollection = query.RunQuery();
foreach (Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem in witCollection)
{
......
}

how to add list of object and return it

Here i am getting the all post and comment accoding to friendID its working fine,my problem is when i debugg it shows me 2 or more data in GetAllPost but its return only last data,i am not getting why its not returning all data at once need help..
public dynamic getalldetails(int friendsid)
{
var GetAllPost = (dynamic)null;
FriendsId =dbContext.Usertable.where(u=>u.userID==friendsid).tolist();
if(FriendsId!=null)
foreach(var item in FriendsId )
{
GetAllPost = (from post in db.Posts.where(item.userID==post.userID).ToList()
orderby post.PostedDate descending
select new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = post.UserProfile.UserName,
PostedByAvatar =imgFolder + (String.IsNullOrEmpty(post.UserProfile.AvatarExt) ? defaultAvatar : post.PostedBy + "." + post.UserProfile.AvatarExt),
PostedDate = post.PostedDate,
PostId = post.PostId,
PostComments = from comment in post.PostComments.ToList()
orderby comment.CommentedDate
select new
{
CommentedBy = comment.CommentedBy,
CommentedByName = comment.UserProfile.UserName,
CommentedByAvatar = imgFolder +(String.IsNullOrEmpty(comment.UserProfile.AvatarExt) ? defaultAvatar : comment.CommentedBy + "." + comment.UserProfile.AvatarExt),
CommentedDate = comment.CommentedDate,
CommentId = comment.CommentId,
Message = comment.Message,
PostId = comment.PostId
}
}).AsEnumerable();
}
return GetAllPost;
}
Each time through the loop, you're assigning to GetAllPost, thereby throwing away whatever it held before. You need to accumulate posts -- something along these lines:
ArrayList GetAllPost = new ArrayList();
...
foreach (var item in FriendsId)
{
GetAllPost.AddRange(from post in
// Your LINQ code
...);
}
return GetAllPost;

Listing in WCF Entity

I have a problem with LINQ query (see comment) there is a First method and it only shows me the first element.
When I write in the console "Sales Representative" it shows me only the first element of it as in
I would like to get all of data about Sales Representative. How can I do it?
public PracownikDane GetPracownik(string imie)
{
PracownikDane pracownikDane = null;
using (NORTHWNDEntities database = new NORTHWNDEntities())
{
//Employee matchingProduct = database.Employees.First(p => p.Title == imie);
var query = from pros in database.Employees
where pros.Title == imie
select pros;
// Here
Employee pp = query.First();
pracownikDane = new PracownikDane();
pracownikDane.Tytul = pp.Title;
pracownikDane.Imie = pp.FirstName;
pracownikDane.Nazwisko = pp.LastName;
pracownikDane.Kraj = pp.Country;
pracownikDane.Miasto = pp.City;
pracownikDane.Adres = pp.Address;
pracownikDane.Telefon = pp.HomePhone;
pracownikDane.WWW = pp.PhotoPath;
}
return pracownikDane;
}
Right now you are just getting the .First() result from the Query collection:
Employee pp = query.First();
If you want to list all employees you need to iterate through the entire collection.
Now, if you want to return all the employee's you should then store each new "pracownikDane" you create in some sort of IEnumerable
public IEnumerable<PracownikDane> GetPracownik(string imie) {
using (NORTHWNDEntities database = new NORTHWNDEntities())
{
var query = from pros in database.Employees
where pros.Title == imie
select pros;
var EmployeeList = new IEnumerable<PracownikDane>();
foreach(var pp in query)
{
EmployeeList.Add(new PracownikDane()
{
Tytul = pp.Title,
Imie = pp.FirstName,
Nazwisko = pp.LastName,
Kraj = pp.Country,
Miasto = pp.City,
Adres = pp.Address,
Telefon = pp.HomePhone,
WWW = pp.PhotoPath
});
}
return EmployeeList;
}
Then, with this returned List you can then do what ever you wanted with them.

Perform group and join using LINQ

Does anyone have any suggestions about how I might do this using just LINQ?
var statements = db.vwOutstandingStatements.ToList();
var amounts = (from s in db.vwOutstandingStatements
group s by s.Id into v
select new
{
Id = v.Key,
amount = v.Sum(a => a.Amount)
}).ToList();
List<vmVendorStatements> statementsToProcess = new List<vmVendorStatements>();
foreach (var amount in amounts)
{
var statement = statements.Find(s => s.Id == amount.Id);
statementsToProcess.Add(new vmVendorStatements()
{
Id = statement.Id,
PropertyAddress = statement.PropertyNumber + " " + statement.PropertyStreet + " " + statement.PropertyTown,
StatementDate = statement.StatementDate.ToLongDateString(),
Amount = amount.amount.ToString()
});
}
Statements is from a sql view via EF5. I run the LINQ to get the data grouped by the sum of the amounts in the returned view and then join it back to show some of the detail from the returned view along with the sums amounts. StatementsToView is my view model to get the data into an MVC view.
I'm sure it could be done in SQL, and I might do that in any case, but there also seems as though there must be a neater solution to the above too.
Thanks,
Jason.
You can just grab out the first item in the group rather than re-querying just to find the first item:
var statementsToProcess =
(from s in db.vwOutstandingStatements
group s by s.Id into v
let first = v.First()
select new vmVendorStatements()
{
Id = v.Key,
amount = v.Sum(a => a.Amount),
PropertyAddress = first.PropertyNumber + " " + first.PropertyStreet + " " + first.PropertyTown,
StatementDate = first.StatementDate.ToLongDateString(),
}).ToList();

Categories