I created a service supporting my asp.net mvc controller. The service returns a List. It is a list of custom defined fields that I render in the the create and edit views. Since these fields are defined once I want to return a cache when available and when not, create the cache. Since I am testing I have not defined cache expiration.
When I execute the Edit action this service helps mapping the queried values to the cached list of customfields. What happens is that my object in cache is modified.
I am familiair that the MemoryCache contains a reference and that is does not contain a copy of the object. What I do not understand is why the MemoryCache is modified, when I am actually working with an object that - in my view - is not a reference to the cache and had been passed to the method and has no ref or out parameters defined. For me the reference is in a totally different scope?
I tried all sorts of things but I am missing the essential issue that is causing this behavior and I really want to figure out what is happening here. Is there a broader scope of the reference. Do local variables are still being shared among methods?
This is the method in the service that either returns the cached information, or queries the database and stores the result in the cache. It is used by the Create and Edit actions. Notice that the value property is defined as being null so that a Create actions starts with empty fields.
public IList<CustomField> GetCustomFields()
{
var result = MemoryCache.Default["cache_customfield"] as List<CustomField>;
if (result == null)
{
result = session.Query<CustomField>()
.AsEnumerable()
.Select(c => new CustomField
{
Id = c.Id,
Name = c.Name,
Value = null
})
.ToList();
MemoryCache.Default["cache_customfield"] = result;
}
return result;
}
public static IList<CustomField> MapValues(IList<CustomField> fields, IDictionary<string,string> values = null)
{
// the cached information still has value properties that are null
var a = MemoryCache.Default["cache_customfield"] as List<CustomField>;
foreach (var field in fields.OrderBy(x => x.Name))
{
var persistedValue = string.Empty;
values?.TryGetValue(field.Id, out persistedValue);
field.Value = persistedValue;
}
// the cached information suddenly has value properties that are defined, however the 'fields' parameter has no reference to the original information?!
var b = MemoryCache.Default["cache_customfield"] as List<CustomField>;
return fields;
}
I doubt these have much impact on the situation, but these are the actions on the controllers for Create and Edit.
public ActionResult Create()
{
var ticketService = BusinessServiceFacade.GetTicketService(RavenSession);
var vm = new TicketViewModel();
vm.Controls = ControlViewModel.CreateControls(ticketService.GetCustomFields());
return View(vm);
}
public ActionResult Edit(string id)
{
var ticketService = BusinessServiceFacade.GetTicketService(RavenSession);
var ticket = RavenSession.Load<Ticket>(id);
var customfieldValues = ticket.Attributes.ToDictionary(x => x.Name, x => x.Value);
var vm = new TicketViewModel(ticket);
var listOfCustomFields = TicketService.MapValues(ticketService.GetCustomFields(), customfieldValues);
vm.Controls = ControlViewModel.CreateControls(listOfCustomFields);
return View(vm);
}
So essentially, why is my cache modified in the MapValues method when the fields parameter has a scope on his own (not ref or out). Really want to understand what is going on here.
UPDATE:
After making the modification by supplying a new List reference I am not noticing any change.
It looks like the reference is still passed forward from the local variable to the newly created as parameter. One thing would be to entirely build up a new list with freshly created CustomField objects but when possible I would like to avoid that.
I am possibly making a simple mistake.
public ActionResult Create()
{
var ticketService = BusinessServiceFacade.GetTicketService(RavenSession);
var vm = new TicketViewModel();
var fields = ticketService.GetCustomFields();
vm.Controls = ControlViewModel.CreateControls(new List<CustomField>(fields));
return View(vm);
}
public ActionResult Edit(string id)
{
var ticketService = BusinessServiceFacade.GetTicketService(RavenSession);
var ticket = RavenSession.Load<Ticket>(id);
var customfieldValues = ticket.Attributes.ToDictionary(x => x.Name, x => x.Value);
var vm = new TicketViewModel(ticket);
var fields = ticketService.GetCustomFields();
var listOfCustomFields = TicketService.MapValues(new List<CustomField>(fields), customfieldValues);
vm.Controls = ControlViewModel.CreateControls(listOfCustomFields);
return View(vm);
}
Solution
Do a deep copy.
public static IList<CustomField> MapValues(IList<CustomField> fields, IDictionary<string,string> values = null)
{
// break reference, deep copy to new list
var oldList = (List<CustomField>) fields;
var newList = oldList.ConvertAll(c => new CustomField(c.Id, c.Name, c.Visible, c.Type, c.TypeFormat, c.Value));
foreach (var field in newList.OrderBy(x => x.Name))
{
var persistedValue = string.Empty;
values?.TryGetValue(field.Id, out persistedValue);
field.Value = persistedValue;
}
return newList;
}
TicketService.MapValues(ticketService.GetCustomFields()...
Within your Edit method, you call MapValues passing in the result of GetCustomFields, and that result is the cached list. So, within MapValues, all of a, b, and fields are references to the same list (the cached object). That's why you see the changes you make to fields also appear in b.
why is my cache modified in the MapValues method when the fields parameter has a scope on his own (not ref or out).
Yes, fields is scoped to the method. But I think you're confusing the difference between 1) changing the value of fields -- which is a reference to a list. And 2) changing the actual list that fields references. Yes, the changes you make to fields is scoped to this method (e.g. it won't affect the value that was passed in). However, as long as it points to a specific list, any changes you make to that list can be observed by other references to the same list. So, the scope of fields doesn't mean the changes you make to the list will be scoped to this method.
In response to the comment below, if you do something like this:
IList<CustomField> originalList = ticketService.GetCustomFields();
IList<CustomField> newList = new List<CustomField>(originalList);
and pass in the new list to MapValues (TicketService.MapValues(newList...) then the changes within MapValues won't affect the list referenced by the originalList. Because now you have two different lists.
Update: As commented below, I didn't notice you were modifying individual items within the list. So you need to deep-copy in that case. In this specific case, deep-copy isn't too bad since you only have a couple properties to copy:
IList<CustomField> originalList = ticketService.GetCustomFields();
IList<CustomField> newList = originalList
.Select(x => new CustomField
{
Id = x.Id,
Name = x.Name,
Value = x.Value
})
.ToList();
However, you can see how this could get problematic quickly as you have more properties or properties of complex types (need to copy properties of properties, etc.). There are solutions such as serializing/deserializing the object to copy but I'd consider a different design first. Like I said, in your case, I think manually copying a couple properties isn't too bad.
Related
I'm using TweetInvi to grab a bunch of tweets that match a specified hashtag. I do this with the following:
var matchingTweets = Search.SearchTweets(hashtag);
This returns an IEnumerable (named ITweet, interface of Tweet), however I cannot create a List<> of Tweets, because Tweet is a static type.
I made, instead, a list of objects, using:
List<object> matches = matchingTweets.Cast<object>().ToList();
However, although each member of the matchingTweets IEnumerable has a number of properties, I cannot access them using:
long tweetID = matches[i].<property>;
Using matches[i].ToString() returns the tweet content, so how can I effectively cast the results in matchingTweets to a list, and subsequently access the properties of those list members? I would ideally like to avoid using dynamic.
In your example above you were trying to grab the ID from the tweet. ITweet implements ITweetIdentifier which contains the Id property. You can literally just access it by:
var matchingTweets = Search.SearchTweets(hashtag);
//Grab the first 5 tweets from the results.
var firstFiveTweets = matchingTweets.Take(5).ToList();
//if you only want the ids and not the entire object
var firstFiveTweetIds = matchingTweets.Take(5).Select(t => t.Id).ToList();
//Iterate through and do stuff
foreach (var tweet in matchingTweets)
{
//These are just examples of the properties accessible to you...
if(tweet.Favorited)
{
var text = tweet.FullText;
}
if(tweet.RetweetCount > 100)
{
//TODO: Handle popular tweets...
}
}
//Get item at specific index
matchingTweets.ElementAt(index);
I don't know exactly what you want to do with all the info, but since the SearchTweets returns a IEnumerable of ITweets you have access to anything an ITweet has defined.
I highly recommend looking through their wiki. It's pretty well organized and gives you clear examples of some basic tasks.
It makes sense you cannot access the properties. You cast it into object so you can only access the objects properties and methods (that like you said might have been overridden).
It should be fine to just access it like this:
List<ITweet> tweets = matchingTweets.Take(5).ToList();
What you can do is project it to a new object of yours:
var tweets = matchingTweets.Select(item => new {
property1 = item.property1,
property2 = item.property2
})
.Take(5).ToList();
Then you will be able to access what you need. Now, if you need to share this data outside the scope of that function create a DTO object and initialize it instead of the anonymous type.
Depending on the size of the project and amount of effort usually it is in any case a good practice to create a layer of DTO objects when you interact with an external service like this. Then if their models changed you can contain your changes only to the DTOs.
If all you want are the ids of the first 5 then:
var ids = matchingTweets.Take(5).Select(item => item.id).ToList();
I have a collection of Employees that I stored inside MemoryCache.Now after update of particular employee details, I want to update the same cache object with updated employee details. Something like that:
var AllEmployees= cache.Get("AllEmployees");
if(AllEmployees != null)
{
var empToUpdate = AllEmployees.FirstOrDefault(i => i.EmpId== Employee.EmpId);
if (empToUpdate != null)
{
AllEmployees.Remove(empToUpdate );
AllEmployees.add(empToUpdate );
}
}
but since cache is memory cache and it has cached IEnumerable<Employee>,i am not able to directly manipulate cache object.I am not able to call these methods FirstOrDefault,Remove,Add
As mentioned in my comment i cant see a reason to no use FirstOrDefault.
IEnumerables are not ment to be modified. So you have to go a heavy, performanceunfirendly way and create a new IEnumerable without a specific item (IENumerable.Except(array of items to exclude)) then yo gonna concat it with another sequenze, which contains your new element to add.
var empToUpdate = AllEmployees.FirstOrDefault(i => i.EmpId== Employee.EmpId);
if (empToUpdate != null)
{
AllEmployees = AllEmployees.Except(new[]{empToUpdate}).Concat(new[] { empToUpdate});
}
Anyways i dont see a sense in this code, cause you are removing the object and immediatly add it again.
I am using a few methods and interfaces in this one. What i need is for the method I'm making to just simply remove 1 value in an array of attributes. All of the stuff here was previously created by someone else, and I'm just creating the removal part for the attribute to be removed. At any rate, the method that does the profile attribute work and sets the value does some work on the back end. I have a method for a UserProfileAttributeSetRequest that looks like this:
public UserProfileAttributeSetRequest()
{
}
public UserProfileAttributeSetRequest(Guid userIdentifier, Dictionary<string, string> profileAttributes)
{
UserIdentifier = userIdentifier;
ProfileAttributes = profileAttributes;
}
This fires a method on the back end that will take in the information being passed to it and change whatever needs to be changed. The method I'm building in the controller probably needs some work, I'm still fairly new to MVC, but here's what I've got:
public ActionResult RemoveEmployeeID(UserInfo userInfo)
{
User usr = UserManager.GetUser(userInfo.UserGuid);
var empID = usr.ProfileAttributes.FirstOrDefault(e => e.ProfileAttributeID == 3);
usr.ProfileAttributes.Remove(empID);
UserProfileAttributeSetRequest upd = new UserProfileAttributeSetRequest();
}
I'm grabbing the complete user, and isolating the single attribute I want to be changed, but the Request complains when I put any parameters in it. What am I doing wrong?
try like this
var emp = usr.ProfileAttributes.Where(e => e.ProfileAttributeID == 3).FirstOrDefault();
usr.ProfileAttributes.Remove(emp);
you have to update the database after removing the item.
I have two similar methods that basically does the same thing only with different objects.
What's the best way to make a generic method out of this if possible?
The two objects:
public class StoreObject {
int Key;
string Address;
string Country;
int Latitude;
int Longitude;
}
public class ProjectObject {
int ProjectKey;
string Address;
string Description;
}
The two methods that I potentially want to make into a generic:
public StoreObject GetStoreByKey(int key)
{
using (DBEntities dbe = new DBEntities())
{
StoreObject so = new StoreObject();
var storeObject = (from s in dbe.StoreTables
where s.Key == key
select s).First();
so.Key = storeObject.key;
so.Address = storeObject.address;
so.Country = storeObject.country;
so.Latitude = storeObject.latitude;
so.Longitude = storeObject.longitude;
return so;
}
}
public ProjectObject GetProjectByKey(int projectKey)
{
using (DBEntities dbe = new DBEntities())
{
ProjectObject po = new ProjectObject();
var projectObject = (from p in dbe.ProjectTables
where p.ProjectKey == projectKey
select p).First();
po.Key = projectObject.p_key;
po.Address = projectObject.p_address;
po.Description = projectObject.p_description;
return po;
}
}
I must note that:
- I have no control over how the table fields are named (ie. p_description).
- StoreTable in the DB, for example, may have other properties (like telephone, postal code, etc) but I'm only interested in showing what I've shown in the code.
- The same goes for the ProjectTable.
Well, the tricky part is that your entities have different properties, so using generics to populate the different properties within one method will not be worth it. But you can return the whole object and then just use the properties you are interested in.
public T GetEntityByKey<T>(int key)
{
using (DBEntities dbe = new DBEntities())
{
return = dbe.StoreTables.Set<T>.Find(new object[] {key});
}
}
And to use it
StoreObject so = GetEntityByKey<StoreObject>(123);
if(so != null)
{
int lat = so.Latitude;
}
You can indeed abstract out the type returned, and factor the using, but for the rest you'd need either a switch on the type requested or, reflection to pass in the fields to retrieve as parameters and the DB query to use.
The former would be bad practice and brings little to the equation, and the latter is costly and can get messy.
This is not really a good candidate for generics, unless you have many of such look-alike methods, in which case I'd go for the reflection approach.
HTH,
Bab.
It's very unlikely that this is your entire 'unit of work' and thus the use of a fresh DBEntities() context in each of these methods is probably the root of your problem here.
Creating a Repository class that includes an instance of the DBEntities class for a single web request (or whatever other unit of request you have in your application) and which has these methods in it would be a better approach to eliminating the duplicate code here. The scope of the using() is then outside these methods and hopefully tied to your web request or other unit of time.
As an option instead of creating a new class you could also extend the DBEntities partial class to include methods like these (assuming this is generated code).
You essentially have two different functionalities in each method:
Query an entity
Map that entity to another type
The first part has been addressed by Steve Mallory.
For the second part, you can use a mapper framework to handle copying values from one instance to another. Since the names of each type do not match, you'll need to tell it how to map names (in your example, adding "p_" and making it lowercase). One possibility would be Emit Mapper.
If you were to factor out all commonality, it would be something like:
public TResult GetById<TResult, TEntity>(int id)
{
using (DBEntities dbe = new DBEntities())
{
T result = dbe.StoreTables.Set<T>.Find(new object[] {key});
var mapper = ObjectMapperManager.DefaultInstance
.GetMapper<TEntity, TResult>(
new DefaultMapConfig().MatchMembers((m1, m2) => "p_" + m1.ToLower() == m2));
return mapper.Map(result);
}
}
Is there a way to add a property to the objects of a Linq query result other than the following?
var query = from x in db.Courses
select new
{
x.OldProperty1,
x.OldProperty2,
x.OldProperty3,
NewProperty = true
};
I want to do this without listing out all of the current properties of my object. There are many properties, and I don't want to have to update this code whenever I may change my class.
I am still learning with LINQ and I appreciate your suggestions.
Add it with partial classes:
public partial class Courses
{
public String NewProperty { get; set; }
}
Then you can assign it after you've created the object.
I suppose you could return a new object composed of the new property and the selected object, like this:
var query = from x in db.Courses
select new
{
Course = x,
NewProperty = true
};
eking's answer will be the most straightforward approach.
If that doesn't work for you (because you need to pass the results around or whatever), and assuming the class you're dealing with already defines the property you want to set, you could create a copy constructor or factory method that takes an existing instance plus the value of the property you want to set:
var query = from x in db.Courses
select new Course(x, valueOfNewProperty);
Alternatively, if Course doesn't define the property, you could subclass it and use the same approach:
var query = from x in db.Courses
select new CourseWithExtraProperty(x, valueOfNewProperty);
(obviously, pick a better name for your subclass)
Again, though, unless you really need to do this, stick with eking's solution.
ServiceStack has a built-in way to handle this with the PopulateWith method.
Here's a code example.
foreach (var item in results)
{
var test1 = new ItemDto().PopulateWith(item);
test1.extraField1 = "extra";
response.Add(test1);
}`
And if you're not using ServiceStack, you can always use AutoMapper.
CreateMap<Foo, Bar>().ForMember(x => x.ExtraBarProperty, opt => opt.Ignore());
If you are looking to dynamically add a property to an object this could be a solution.
This is what has worked for me, I also had a concern and it was what happened with those domain objects that had many properties, the maintainability for any changes in the object was absurd, I managed to build an implementation with LINQ - ExpandObject - Reflection, which helped to keep my object dynamic and only add the additional properties that my view logic required.
var expandedModel = db.Courses.Select(x =>
{
dynamic expandObject = new ExpandoObject();
expandObject.NewProperty= $"PropertyValue";
foreach (var property in x.GetType().GetProperties())
{
((IDictionary<string, object>)expandObject).Add(property.Name, property.GetValue(x));
}
return expandObject;
}).ToList();