我正在研究一种从数据库检索记录集合的方法。记录根据它们包含的数据的一个方面存储在单独的表中。假设它看起来像这样。
public class EnglishPhrase : IPhrase
{
public string Text {get; set;}
}
public class SpanishPhrase: IPhrase
{
public string Text {get; set;}
}
// This is actually a DbContext with DbSets.
// I have not implemented DbContext in this example to
// alleviate overhead when reproducing the situation.
public class MyContext
{
public EnglishPhrase[] EnglishPhrases { get; set; }
public SpanishPhrase[] SpanishPhrases { get; set; }
}
我的方法需要根据语言参数选择英语或西班牙语短语。现在,我用一个switch
语句来完成它。
public IEnumerable<IPhrase> GetPhrases(string language)
{
IEnumerable<IPhrase> result = null;
MyContext context = new MyContext();
switch(language)
{
case "English":
result = context.EnglishPhrases.ToList();
break;
case "Spanish":
result = context.SpanishPhrases.ToList();
break;
default:
throw new Exception();
}
return result;
}
我使用了switch
,因为稍后我将添加更多的语言,但这意味着我每次这样做都必须修改此方法。但是,我禁不住觉得有更好的方法可以做到这一点。
我是否可以做其他事情,例如向Language
接口添加IPhrase
属性,这将允许我的方法以这种方式访问正确的DbSet
,或者是{{ 1}}完成目标的最捷径?
答案 0 :(得分:0)
这就是我的想法。更像伪代码一样对待它。您需要使其适合您的场景。但是包括了开闭原理的主要概念。我使用泛型类来构建语言对象。
如果要添加更多语言,只需创建新类。您可以创建某种语言课,然后英语课(和其他语言)可以从中继承。
您可以使用依赖注入,并且只需使用接口即可操作。
public interface IPhrase<T>
{
string Text { get; set; }
}
public class Phrase<T> : IPhrase<T> where T : Language
{
public string Text { get; set; }
public DbSet<T> DbSet { get; set; }
public Phrase(string text, DbContext context)
{
Text = text;
DbSet = context.Set<T>();
}
}
public class Language
{
//do smth
}
public class English : Language
{
//do smth
}
public class Spanish : Language
{
//do smth
}
用法:
DbContext _context = new DbContext();
Phrase<English> en = new Phrase<English>("Your english text goes here", _context);
public IEnumerable<IPhrase<T>> GetPhrases(Phrase<T> language)
{
return language.DbSet.ToList();
}
GetPhrases方法甚至可以放在短语类中。
我希望它能对您有所帮助。祝你好运!
答案 1 :(得分:0)
您可以在IPhrase模型中包括一个“语言”属性。然后,当您加载上下文时: 结果= context.Where(p => p.Language == languageParam).ToList()
不确定这对您来说是否更简单
答案 2 :(得分:0)
您可以使用TPH简化上下文和操作。
型号:
public enum PhraseType
{
English,
Spanish
}
public abstract class Phrase
{
public int Id { get; set; }
public string Text { get; set; }
public PhraseType PhraseType { get; set; }
}
public class EnglishPhrase : Phrase {}
public class SpanishPhrase : Phrase {}
DbContext:
public DbSet<Phrase> Phrases { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.Entity<Phrase>()
.HasDiscriminator(p => p.PhraseType)
.HasValue<EnglishPhrase>(PhraseType.English)
.HasValue<SpanishPhrase>(PhraseType.Spanish);
}
操作方法:
public IEnumerable<Phrase> GetPhrases(string language)
{
// assuming the language parameter is "english" or "spanish"
var theType = $"YourNamespace.{language}Phrase";
//assuming your models are in the current assembly
Type type = TypeInfo.GetType(theType, true, true);
MethodInfo method = typeof(Queryable).GetMethod("OfType").MakeGenericMethod(type);
var obj = appContext.Phrases.AsQueryable();
var result = method.Invoke(obj, new[] { obj });
return result as IEnumerable<Phrase>;
}
一些解释:
您使用TPH(每个层次结构的表),因此只需创建一个DbSet
。
要返回所有EnglishPhrase
时,可以使用context.Phrases.OfType<EnglishPhrase>()
,但是由于参数确定类型,因此需要使用反射来调用正确的OfType
方法。
您可以将所有这些反射代码放入帮助程序类中,以便您的操作更加简洁。
将来,当您想添加更多语言时,只需编辑PhraseType
枚举并在Fluent API中添加额外的HasValue
。无需更改Action方法。
我刚刚在系统上对其进行了测试,并且可以正常工作。