我想在asp.net mvc中缓存数据集并过滤此集合而不更改缓存集合。
是否可以这样做?
因为现在,当我获得我的缓存集合时,我会得到它的引用,并且过滤此集合的数据会更改缓存的集合。
有人知道吗?
答案 0 :(得分:4)
只需将缓存列表中的项目复制到新列表即可。实例将是相同的,但不会触及原始(缓存)列表。像这样:
List<[CLASS]> collectionCached; //assuming this this your cached list
List<[CLASS]> collectionWorking = new List<[CLASS]>();
collectionWorking.AddRange(collectionCached);
这将允许您过滤掉所需的任何实例,而无需触及原始(缓存)列表。
编辑:
在OP进一步澄清之后,似乎需要制作实体本身的副本。制作参考对象副本的基本思想称为“克隆”。这将生成原始实体的副本,并允许您在不更改原始实例的情况下更改副本。 SO有一些很好的链接,这里讨论克隆和LINQ的概念。
How to get a copy of data instead of a reference using linq/lambda in c#?
这可以让你走上正轨。如果您有任何其他问题,请与我们联系。
答案 1 :(得分:3)
Malcolm Frexner所说的是一种解决问题的简洁方法,但使用AutoMapper可以大大简化。
假设您有一个正在从中提取DTO对象的适配器(或者如果您直接从数据库中提取WCF,则使用WCF,同样的概念适用)
public class AccountServiceAdapter
{
private List<Accounts> _accounts
{
get
{
if(HttpContext.Current.Cache["accounts"] == null)
HttpContext.Current.Cache["accounts"] = default(List<Accounts>());
return (List<Accounts>)HttpContext.Current.Cache["accounts"];
}
set
{
HttpContext.Current.Cache["accounts"] = value;
}
}
public List<AccountViewModel> FetchAccounts()
{
if(_accounts == default(List<Accounts>))
{
//Do Fetch From Service or Persistence and set _accounts
}
return _accounts.Select(x => x.ConvertToViewModel()).ToList();
}
}
那就是你可能已经写好的缓存片了。接下来是您可以享受一些乐趣的地方。我不会解释AutoMapper的所有映射乐趣,因为有十亿个链接可以做到,但我会给你一些片段来帮助你。
https://github.com/AutoMapper/AutoMapper/wiki/Projection
使用NuGet添加对AutoMapper的引用后,您需要创建一个ProjectionManager类。
public static class ProjectionManager
{
ProjectionManager()
{
//The mapping exercise is AS SIMPLE as this if all you are doing is
//using the exact same property names, it'll autowire
//If you use different projections you can create complex maps see the link
//above.
Mapper.CreateMap<Account,AccountViewModel>();
Mapper.CreateMap<AccountViewModel,Account>();
}
//Make yourself some handy extension methods for syntactic sugar
public static AccountViewModel ConvertToViewModel(this Account x)
{
return Mapper.Map<Account,AccountViewModel>(x);
}
//Make yourself some handy extension methods for syntactic sugar
public static Account ConvertFromViewModel(this AccountViewModel x)
{
return Mapper.Map<AccountViewModel,Account>(x);
}
}
完成所有这些操作后,您的缓存现在变得非常简单,启动后您可以将数据转换为具有验证,显示名称等所有简洁功能的视图模型,而不必弄乱您的实体对象或您的DTO对象退出WCF服务!
答案 2 :(得分:2)
这应该有效:
IEnumerable<T> things = GetThings();
Cache["ThingCache"] = things;
T aThing = ((IEnumerable)Cache["ThingCache"]).First();
//Cache["ThingCache"] should still contain the original collection.
答案 3 :(得分:2)
缓存完整列表,然后使用Linq过滤集合。
var list = GetFromCache();
var filtered = list.Where(x => x.Name.Contains("rob"));
编辑:
获得此筛选列表时,是否要更改列表中包含的对象?是的,这也将反映在缓存列表中的同一个实例中。但在这一点上,听起来这不是很好的缓存数据。通常,缓存的数据不会更改,或者您可以在一段时间内看不到更改。如果数据准确性更重要,请不要缓存。
如果你要更改列表中的项目状态,你或许可以得到你想要的东西:
var filtered = list.Where(x => x.Name.Contains("rob")).Select(x => x.MemberwiseClone()).Cast<YourObjType>();
这使用MemberwiseClone执行浅拷贝;如果这还不够好,你需要对一个保存副本的方法做一些工作。它返回Object,因此我使用Cast扩展方法将其恢复为最初在列表中的对象类型。
答案 4 :(得分:2)
我终于通过在每个对象中创建一个Clone()方法来解决我的问题,并在从缓存中检索它之后立即调用我的主对象上的Clone()方法。
我的主要对象是类型帐户,其中包含自己的域名列表,其中包含产品列表等...
以下是Account对象中的Clone方法:
public Account Clone()
{
// Copy all properties of the object in a new object account
var account = (Account)this.MemberwiseClone();
var domainsList = new List<Domain>();
foreach (var d in this.Domains)
{
domainsList.Add(d.Clone());
}
account.Domains = domainsList;
return account;
}
就像你可以看到我使用MemberwiseClone()来复制简单属性,然后我再次在所有复杂对象上调用Clone。克隆,这是我在所有复杂对象中创建的自定义方法。
现在它工作正常......
答案 5 :(得分:2)
当我在View中直接使用我的域模型时遇到了这个问题。只要将所有显示的数据放在专用的ViewModel中,就可以轻松解决问题。
<强>的DomainModel 强>
public class PersonInfo
{
public int Age {get;set;}
public string Name {get;set;}
}
<强>视图模型强>
public class PersonViewModel
{
public PersonInfo PersonData {get;set;}
public bool Visible {get;set;}
}
现在,您可以将PersonInfo存储在缓存中,而不会为所有用户存储“Visible”属性。
如果你有对象列表会有点困难,但这种模式适用于那里。
答案 6 :(得分:1)
最简单的方法是将对象序列化为json,然后再将它们放入缓存中,然后在将它们移出缓存时进行反序列化。 这样您就不必对类进行任何更改,例如实现iclonable或类似的。
Cache.Set(key, JsonConvert.SerializeObject(objectToCache), policy);
然后
var cachedObject = (string)Cache[ComposeKey(key, domain)];
return JsonConvert.DeserializeObject<T>(cachedObject);
答案 7 :(得分:0)
这是处理缓存中毒时的首选代码:
var list_from_cache = HttpContext.Current.Cache["females"] as List<Females>;
var females = new List<Females>();
females.AddRange(list_from_cache.Select(n => Cloner(n))); //clone all objects
//now we can change the objects as much as we want without changing the cache
females[0].Height=160;
克隆人的代码,把它放在某个地方:(记得把[Serializable]放在你的类上克隆)
public static T Cloner<T>(T source) where T : class
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
//return (T)formatter.Deserialize(stream);
var clone = formatter.Deserialize(stream) as T;
return clone;
}
}
答案 8 :(得分:0)
这可以使用System.Collections.Immutable解决。
您正在寻找ImmutableList。
在此处获取nuget-package:https://www.nuget.org/packages/System.Collections.Immutable/ 或:Install-Package System.Collections.Immutable