Schnittstelle Lösung
Wenn Sie Ihrem Objekt eine Schnittstelle hinzufügen können, können Sie das verwenden. Zum Beispiel könnten Sie definieren:
public interface IName
{
string Name { get; }
}
Dann könnte Ihr Repository deklariert werden als:
class Repository<T> where T:class, IName
{
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => i.Name == keyword);
}
}
Alternate-Interface-Lösung
Alternativ Sie die "where" auf SearchExact Methode setzen könnte durch Verwenden eines zweiten generischen Parameters:
class Repository<T> where T:class
{
public IQueryable<T> SearchExact<U>(string keyword) where U: T,IName
{
return db.GetTable<U>().Where(i => i.Name == keyword);
}
}
Dadurch kann die Repository-Klasse mit Objekten verwendet werden, die IName nicht implementieren, während die SearchExact-Methode nur mit Objekten verwendet werden kann, die IName implementieren.
Reflection Lösung
Wenn Sie keine Iname-ähnliche Oberfläche, um Ihre Objekte hinzufügen können, können Sie Reflexion statt:
class Repository<T> where T:class
{
static PropertyInfo _nameProperty = typeof(T).GetProperty("Name");
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => (string)_nameProperty.GetValue(i) == keyword);
}
}
Dies ist langsamer als eine Schnittstelle verwendet, aber manchmal Es ist der einzige Weg.
Weitere Hinweise zur Interface-Lösung und warum Sie es vielleicht
In Ihrem Kommentar verwenden Sie erwähnen, dass Sie nicht über eine Schnittstelle verwenden können, aber nicht erklären, warum. Du sagst: "Nichts ist in den drei Modellen vorhanden. Daher denke ich, dass es unmöglich ist, eine Schnittstelle daraus zu machen." Aus Ihrer Frage habe ich verstanden, dass alle drei Modelle eine "Name" -Eigenschaft haben. In diesem Fall ist es ist möglich, eine Schnittstelle auf allen drei zu implementieren. Implementieren Sie einfach die Schnittstelle wie gezeigt und ", IName" zu jeder Ihrer drei Klassendefinitionen. Dadurch erhalten Sie die beste Leistung für lokale Abfragen und SQL-Generierung.
Auch wenn die fraglichen Eigenschaften nicht alle als "Name" bezeichnet werden, können Sie die nterface-Lösung dennoch verwenden, indem Sie jeder Eigenschaft eine "Name" -Eigenschaft hinzufügen und deren Getter und Setter auf die andere Eigenschaft zugreifen.
Expression Lösung
Wenn die Iname Lösung nicht funktionieren, und Sie müssen die SQL-Umwandlung zu arbeiten, können Sie dies tun, indem Sie Ihre LINQ-Abfrage mit Ausdrücken zu bauen. Dies ist mehr Arbeit und ist für die lokale Verwendung deutlich weniger effizient, wird aber gut zu SQL konvertieren. Der Code würde wie folgt sein:
class Repository<T> where T:Class
{
public IQueryable<T> SearchExact(string keyword,
Expression<Func<T,string>> getNameExpression)
{
var param = Expression.Parameter(typeof(T), "i");
return db.GetTable<T>().Where(
Expression.Lambda<Func<T,bool>>(
Expression.Equal(
Expression.Invoke(
Expression.Constant(getNameExpression),
param),
Expression.Constant(keyword),
param));
}
}
und es würde thusly genannt werden:
repository.SearchExact("Text To Find", i => i.Name)
Quer denken, ich mag es. Linq2Sql bedeutet, dass sie wahrscheinlich einige Nachbearbeitung verwenden müssen, um die Schnittstelle auf die Klassen anzuwenden. – Spence
Der zweite Ansatz (Constraint auf Methode) scheint mir besser, würde aber wahrscheinlich dann die Methode SearchExactName umbenennen. –
@Spence - es gibt zwei Möglichkeiten, dies zu tun; Sie können entweder partielle Klassen verwenden, um '' IName' hinzuzufügen, oder Sie können die DBML bearbeiten und den globalen Basistyp für Entitäten festlegen (falls alle Ihre Typen dies implementieren sollten). –