问题描述
您好,我正在尝试这样做:
我有更多的类供用户存储文件-这些文件的路径以JSON格式存储在数据库中,文件存储在名为该类的文件夹中(因此,当类名称为Foo时,文件将存储在Files / Foo / Foobar.pdf)。
我有一个控制器,用于将路径发送到应删除的文件。在这里,我不能解决这个问题,我也需要从数据库中删除该文件路径,但是我无法找到如何动态获取DbSet的方法。
我在这里搜索了许多问题,但是几乎每次我都找到DbContext.Set()时,但是ASP.NET CORE 3.0中不存在此方法。你能帮我怎么做吗?
这是我的控制器:
[HttpGet]
public JsonResult DeleteFile(string id)
{
keyvaluePair<string,string> message;
if (!string.IsNullOrEmpty(id))
{
string filePath = Uri.UnescapeDataString(id);
if (filePath.CheckIfExists())
{
string nameOfInstance = filePath.GetNumberAccordingToFileName();
string tableName = filePath[1..(filePath.IndexOf('/',1) - 1)];
Type type = Assembly.GetExecutingAssembly()
.GetTypes()
.FirstOrDefault(t => t.Name.Equals(tableName,StringComparison.OrdinalIgnoreCase));
if(type.IsClass)
{
var entity = db.GetDbSet(Activator.CreateInstance(type)); //this is not working
var item = entity.GetDataFromDbase(nameOfInstance,1,"Number","ASC",false,out int filteredResultsCount,out int totalResultsCount,false).FirstOrDefault(); //find the item
item = item.DeleteFileFromItem(User.Identity.Name,filePath);
db.Update(item);
var result = db.SaveChanges();
if (result > 0)
{
if (filePath.DeleteFile())
{
message = new keyvaluePair<string,string>(MessagesHandler.Success,$"File {filePath.Substring(filePath.LastIndexOf("/"))} was successfully deleted.");
return Json(new
{
status = true,message
});
}
else
{
message = new keyvaluePair<string,string>(MessagesHandler.Error,$"File {filePath.Substring(filePath.LastIndexOf("/"))} was not deleted.");
return Json(new
{
status = false,message
});
}
} //if the changes were not made in DB
message = new keyvaluePair<string,$"File {filePath.Substring(filePath.LastIndexOf("/"))} was deleted,error in DB");
return Json(new
{
status = false,message
});
}
}//error message when file not found
message = new keyvaluePair<string,$"File {filePath} not found.");
return Json(new
{
status = false,message
});
}//error message when filename is empty
message = new keyvaluePair<string,$"Field ID cannot be empty");
return Json(new
{
status = false,message
});
}
这是GetDbSet方法:
public static Microsoft.EntityFrameworkCore.DbSet<TEntity> GetDbSet<TEntity>(this DataContext db,TEntity t) where TEntity : class
{
Type type = t.GetType();
return (Microsoft.EntityFrameworkCore.DbSet<TEntity>)typeof(DataContext).getmethod(nameof(DataContext.Set)).MakeGenericmethod(type).Invoke(db,null);
}
我在这里遇到了这个异常:
system.invalidCastException HResult = 0x80004002 Message =无法转换类型为“ Microsoft.EntityFrameworkCore.Internal.InternalDbSet
1[SmartLab_System.Models.TestRequirement]' to type 'Microsoft.EntityFrameworkCore.DbSet
1 [System.Object]”的对象。
方法GetDataFromDbase:
public static List<T> GetDataFromDbase<T>(this IEnumerable<T> entity,string searchBy,int take,int skip,string sortBy,string sortDir,string columnName,bool showDeactivatedItems,bool countResult = true) where T : class
{
IEnumerable<T> helper;
if (!String.IsNullOrEmpty(searchBy))//if any string to search was given
{
//find the properties we would like to search in
var properties = typeof(T).GetProperties()
.Where(x => x.CanRead && columnName.Contains(x.Name,StringComparison.InvariantCultureIgnoreCase) && columnName.Length == x.Name.Length)
.Select(x => x.getmethod)
.Where(x => !x.Isstatic);
//.ToList();
//list of all items where searched value was found
helper = entity.GetActiveItems(showDeactivatedItems)
.Where(m => properties
.Select(p => p.Invoke(m,null)?.ToString() ?? string.Empty)
.Any(a => a.ToString().Contains(searchBy,StringComparison.InvariantCultureIgnoreCase)) == true);
//.ToList();
}
else//if no string to search was given
{
helper = entity.GetActiveItems(showDeactivatedItems); //all items
}
List<T> result;
if (take < 1)
{
result = helper
.OrderBy(sortBy + " " + sortDir)
.ToList();
}
else
{
result = helper
.OrderBy(sortBy + " " + sortDir)
.Skip(skip)
.Take(take)
.ToList();
}
if (countResult)
{
filteredResultsCount = helper.Count();//how many items is sent
totalResultsCount = entity.Count(); //how many items is in database
}
else
{
filteredResultsCount = 0;//how many items is sent
totalResultsCount = 0;
}
return result;
}
除了打电话给db.GetDbSet(type)
外,我也尝试了db.GetDbSet(Activator.CreateInstance(type))
但不起作用。
解决方法
我在评论(Dynamically access table in EF Core 2.0中发布的链接将为您检索该集合,但是您无法对其进行操作,因为它的类型为IQueryable
而不是IQueryable<T>
。
我认为通过在实体上使用简单的开关和通用接口,可以为您提供更好的解决方案。只要您的数据库中没有100个以上的表,这将很容易维护。
var entityType = "Drawer";
var pathToRemove = "somepath";
var id = 1;
// get queryable based on entity type
IQueryable<IHasFiles> queryable = entityType switch
{
"Drawer" => context.Set<Drawer>().OfType<IHasFiles>(),"Bookshelf" => context.Set<Bookshelf>().OfType<IHasFiles>(),_ => throw new ArgumentException("Unknown entity type",nameof(entityType))
};
// pick the item and include all files
var item = await queryable.Where(i => i.Id == id).Include(i => i.Files).SingleAsync();
// pick the correct file
var file = item.Files.Single(f => f.Path == pathToRemove);
// remove it
item.Files.Remove(file);
// save changes to db
await context.SaveChangesAsync();
在实体中定义了类似的内容
public interface IHasFiles
{
int Id { get; }
ICollection<File> Files { get; set; }
}
public class File
{
public int Id { get; set; }
public string Path { get; set; }
}
public class Drawer : IHasFiles
{
public int Id { get; set; }
public ICollection<File> Files { get; set; }
}
public class Bookshelf : IHasFiles
{
public int Id { get; set; }
public ICollection<File> Files { get; set; }
}