I'd like to know if there is a way or more efficient way using Linq. Instead of using the while loop, is it possible to do a select where using Linq query?
public UserPrincipal GetUser(string sUserName, string spwd, string domain, string ou)
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, domain, ou, sUserName, spwd);
UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
DirectoryEntry user = (DirectoryEntry)oUserPrincipal.GetUnderlyingObject();
PropertyCollection pc = user.Properties;
IDictionaryEnumerator ide = pc.GetEnumerator();
ide.Reset();
while (ide.MoveNext())
{
PropertyValueCollection pvc = ide.Entry.Value as PropertyValueCollection;
if (ide.Entry.Key.ToString() == "XYZ")
{
//Response.Write(string.Format("name: {0}", ide.Entry.Key.ToString()));
//Response.Write(string.Format("Value: {0}", pvc.Value));
}
}
.......;
.......;
}
Thanks!
The reason you can't use Where() on a PropertyCollection is because it implements the non-generic IEnumerable, when Where() is a method of only the generic version. You can convert a PropertyCollection to a generic IEnumerable by using Cast<T>().
var matches = pc.Cast<DictionaryEntry>().Where(p => p.Key.ToString() == "XYZ");
foreach( var match in matches )
{
Response.Write(string.Format("name: {0}", match.Key));
Response.Write(string.Format("Value: {0}", match.Value));
}
This way is doubtfully any more efficient.
Try this:
foreach (PropertyValueCollection pvc in pc.OfType<PropertyValueCollection>().Where(v => v.PropertyName == "XYZ"))
{
Response.Write(string.Format("name: {0}", pvc.PropertyName));
Response.Write(string.Format("Value: {0}", pvc.Value));
}
Besides, you can try to use ForEach:
pc.OfType<PropertyValueCollection>()
.Where(v => v.PropertyName == "XYZ")
.ToList()
.ForEach(pvc =>
{
Response.Write(string.Format("name: {0}", pvc.PropertyName));
Response.Write(string.Format("Value: {0}", pvc.Value));
});
This is a pretty old thread, but I was searching for a way to work with PropertyCollection using LINQ. I tried the suggested methods, but I always get an invalid cast exception when casting to DictionaryEntry. And with a DictionaryEntry, things like FirstOrDefault are funky. So, I simply do this:
var directoryEntry = adUser.GetUnderlyingObject() as DirectoryEntry;
directoryEntry.RefreshCache();
var propNames = directoryEntry.Properties.PropertyNames.Cast<string>();
var props = propNames
.Select(x => new { Key = x, Value = directoryEntry.Properties[x].Value.ToString() })
.ToList();
With that in place, I can then easily query for any property directly by Key. Using the coalesce and safe navigation operators allows for defaulting to an empty string or whatever..
var myProp = props.FirstOrDefault(x => x.Key == "someKey"))?.Value ?? string.Empty;
Note that the "adUser" object is the UserPrincipal object.
Related
There are many tables in the database that are used as "lookup" tables. All the tables have the same structure, other than the ID column name.
I have found that I can use reflection to open a table and enumerate through the records. The method takes a string (tableName).
Uri serviceUri = new Uri("http://localhost/MyDataService/WcfDataService.svc");
var context = new MyEntities(serviceUri);
var eTable = typeof(MyEntities).GetProperty(tableName).GetValue(context, null) as IEnumerable<object>
foreach (object o in eTable)
...
This works fine, but I want to add a WHERE clause to the query. For example, where InactiveDate == null.
Can I do this? I have been unable to figure this one out.
How about this?
var eTable = (typeof(MyEntities).GetProperty(tableName).GetValue(context, null) as IEnumerable<object>).Where(obj => obj.GetType().GetProperty("InactiveDate").GetValue(obj) == null);
foreach (object o in eTable)
I would suggest to use generics and maybe an interface over reflection.
public function Xyz<TEntity>(Func<MyEntities, IDbSet<TEntity>> dbSetGetter, Expression<Func<TEntity, Boolean>> filter)
{
var serviceUri = new Uri("http://localhost/MyDataService/WcfDataService.svc");
using (var context = new MyEntities(serviceUri))
{
foreach (var entity in dbSetGetter(context).Where(filter))
{
DoSomethingWith(entity);
}
}
}
Usage would be like this
Xyz(context => context.Foo, foo => foo.Bar == 42);
assuming you have an entity Foo with an integer property Bar. The obvious difference to your code is that you have to know the entity type a compile time and I am not sure if you know it then.
I have method which accept expression for Linq Where clause. Sometimes I would like to ignore Where clause and do not use it.
I have tried to pass null to the method like this
GetUsersView(null)
but got exception. How correctly do this?
private IQueryable<UserView> GetUsersView(Expression<Func<User, bool>> expression)
{
return _userRepository.GetAll().
Where(expression).
Select(p => new UserView
{
Id = p.Id,
Active = p.Orders.Any(c => c.Active && (c.TransactionType == TransactionType.Order || c.TransactionType == TransactionType.Subscription)),
DateStamp = p.DateStamp,
Email = p.Email,
FirstName = p.FirstName,
LastName = p.LastName,
Message = p.Message,
UsersManager = p.Orders.Select(o => o.Product).Any(w => w.UsersManager && w.Active)
});
}
Passing nulls to methods is a horrible idea. Passing u => true is not very readable either. Create two methods instead - one which has parameter, and other, which don't have. Also I see your method have two responsibilities - it filters users, and converts them to UserViews. I think filtering users by predicate should occur in repository.
You can also create extension method IQueryable<UserView> ToViews(this IQueryable<User> source).
public static IQueryable<UserView> ToViews(this IQueryable<User> source)
{
return source.Select(u => new UserView
{
Id = u.Id,
Active = u.Orders.Any(o => o.Active &&
(o.TransactionType == TransactionType.Order ||
o.TransactionType == TransactionType.Subscription)),
DateStamp = u.DateStamp,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
Message = u.Message,
UsersManager = u.Orders.Select(o => o.Product)
.Any(p => p.UsersManager && p.Active)
});
}
In this case code will look like:
private IQueryable<UserView> GetUserViews()
{
return _userRepository.GetAll().ToViews();
}
private IQueryable<UserView> GetUserViews(Expression<Func<User, bool>> predicate)
{
// move filtering to repository
return _userRepository.GetAll(predicate).ToViews();
}
Try using
GetUsersView(u=>true);
or if you would prefer not to type the expression all the time, you can create an overloaded function that provides a default expression.
IQueryable<UserView> GetUsersView()
{
return GetUsersView(u=>true);
}
I am trying to replace a string date value "01/01/1700" with an empty string in LINQ.
The date is of type string.
Something like this but I cant get it to work.
Query<Client>(sql).ToList().ForEach(x => x.DateOfBirth =
x.DateOfBirth.Replace("01/01/1700", ""));
This code works but its not LINQ.
var result = Query<Client>(sql).ToList();
foreach (var client in result)
{
if (client.DateOfBirth == "01/01/1700")
{
client.DateOfBirth = "n/a";
}
}
Thanks for your help.
The problem is the ToList(). The result is not visible in the variable you use afterwards.
Try out the following:
var list = Query<Client>(sql).ToList();
list.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Should work fine. Use the list variable afterwards.
var result = Query<Client>(sql).ToList();
result.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Your code assumes that changes made to an object in a List will be reflected in the Query<Client> that the object came from. Apparently this is not the case. One thing you could try is assigning the list before calling ForEach() and using the list from that point on:
var clients = Query<Client>(sql).ToList();
clients.ForEach(x => x.DateOfBirth = x.DateOfBirth.Replace("01/01/1700", ""));
Also, ForEach is not a LINQ operator. It is a method in the List class. Unlike LINQ operators, it will modify the list that called it and will not return anything. The way to "modify" data with LINQ is by using select:
var clients = (from client in Query<Client>(sql).ToList()
select new Client(client)
{
DateOfBirth = client.DateOfBirth.Replace("01/01/1700", "")
}).ToList();
Hi I have a query like this:
var queryGridData = from question in questions
select new {
i = question.Id,
cell = new List<string>() { question.Id.ToString(), question.Note, question.Topic }
};
The ToString() part needed to convert the int is causing:
LINQ to Entities does not recognize the method 'System.String.ToString()' method, and this method cannot be translated into a store expression.
Hmmmmmmmmmmm. I need it as a string to go into the collection. Any ideas?
I would personally perform just enough of the query in the database to provide the values you want, and do the rest in .NET:
var queryGridData = questions.Select(q => new { q.Id, q.Note, q.Topic })
.AsEnumerable() // Do the rest locally
.Select(q => new { i = q.Id,
cell = new List<string> {
q.Id.ToString(),
q.Note,
q.Topic
} });
(This formatting is horrible, but hopefully it'll be easier to do nicely in an IDE where you've got more space :)
I am having some trouble with a linq query I am trying to write.
I am trying to use the repository pattern without to much luck. Basically I have a list of transactions and a 2nd list which contains the description field that maps against a field in my case StoreItemID
public static IList<TransactionViewModel> All()
{
var result = (IList<TransactionViewModel>)HttpContext.Current.Session["Transactions"];
if (result == null)
{
var rewardTypes = BusinessItemRepository.GetItemTypes(StoreID);
HttpContext.Current.Session["Transactions"] =
result =
(from item in new MyEntities().TransactionEntries
select new TransactionViewModel()
{
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
}).ToList();
}
return result;
}
public static List<BusinessItemViewModel>GetItemTypes(int storeID)
{
var result = (List<BusinessItemViewModel>)HttpContext.Current.Session["ItemTypes"];
if (result == null)
{
HttpContext.Current.Session["ItemTypes"] = result =
(from items in new MyEntities().StoreItems
where items.IsDeleted == false && items.StoreID == storeID
select new BusinessItemViewModel()
{
ItemDescription = items.Description,
StoreID = items.StoreID,
StoreItemID = items.StoreItemID
}).ToList();
}
return result;
However I get this error
Unable to create a constant value of type 'MyMVC.ViewModels.BusinessItemViewModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
I know its this line of code as if I comment it out it works ok
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
How can I map ItemDescription against my list of itemTypes?
Any help would be great :)
This line has a problem:
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription,
Since you are using FirstOrDefault you will get null as default value for a reference type if there is no item that satifies the condition, then you'd get an exception when trying to access ItemDescription - either use First() if there always will be at least one match or check and define a default property value for ItemDescription to use if there is none:
ItemDescription = itemTypes.Any(r=>r.StoreItemID==item.StoreItemID)
? itemTypes.First(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription
: "My Default",
If itemTypes is IEnumerable then it can't be used in your query (which is what the error message is telling you), because the query provider doesn't know what to do with it. So assuming the that itemTypes is based on a table in the same db as TransactionEntities, then you can use a join to achieve the same goal:
using (var entities = new MyEntities())
{
HttpContext.Current.Session["Transactions"] = result =
(from item in new entities.TransactionEntries
join itemType in entities.ItemTypes on item.StoreItemID equals itemType.StoreItemID
select new TransactionViewModel()
{
ItemDescription = itemType.ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
CustomerName = rewards.CardID//TODO: Get customer name
}).ToList();
}
I don't know the structure of your database, but hopefully you get the idea.
I had this error due a nullable integer in my LINQ query.
Adding a check within my query it solved my problem.
query with problem:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.Equals(y.OBJ_ID));
query with problem solved:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.HasValue && s.Obj_Id.Value.Equals(y.OBJ_ID));