C# 如何在使用空间类型和自动映射时优化实体框架查询?
我正在建设的东西不是很独特。简而言之,我正在使用ASP.NETMVC4(WebAPI)和EntityFramework5(具有空间支持)在Azure中创建一个类似FourSquare的小服务。所以我使用的是SQLAzure,而不是像MongoDB或CouchDB这样的NoSQL数据库。部分原因是我对.NET更为熟悉,部分原因是为了了解开发经验(重构、部署、测试),部分原因是为了了解它将如何与node.js/MongoDB相抗衡 现在让我们看一些代码C# 如何在使用空间类型和自动映射时优化实体框架查询?,c#,linq,entity-framework-5,spatial,automapper-2,C#,Linq,Entity Framework 5,Spatial,Automapper 2,我正在建设的东西不是很独特。简而言之,我正在使用ASP.NETMVC4(WebAPI)和EntityFramework5(具有空间支持)在Azure中创建一个类似FourSquare的小服务。所以我使用的是SQLAzure,而不是像MongoDB或CouchDB这样的NoSQL数据库。部分原因是我对.NET更为熟悉,部分原因是为了了解开发经验(重构、部署、测试),部分原因是为了了解它将如何与node.js/MongoDB相抗衡 现在让我们看一些代码 /// <summary> ///
/// <summary>
/// Return the nearest locations relative from the given longitude/latitude
/// </summary>
/// <param name="longitude">Longitude</param>
/// <param name="latitude">Latitude</param>
/// <param name="maxresults">Optional maximum results, default is 2</param>
/// <param name="radius">Optional maximum radius in kilometres, default is 50 km</param>
/// <returns></returns>
public JsonEnvelope Get(string longitude, string latitude, int maxresults = 2, int radius = 50)
{
var pointTxt = string.Format("POINT({0} {1})", longitude, latitude);
var locations = (from s in locationEntityRepository.GetAll
orderby s.Coordinates.Distance(DbGeography.FromText(pointTxt))
where s.Coordinates.Distance(DbGeography.FromText(pointTxt)) / 1000 <= radius
select new Location
{
Id = s.Id,
Name = s.Name,
LocationType = s.LocationType,
Address = s.Address,
Longitude = s.Coordinates.Longitude.Value,
Latitude = s.Coordinates.Latitude.Value,
Distance = (s.Coordinates.Distance(DbGeography.FromText(pointTxt)).Value) / 1000
})
.Take(maxresults).ToList();
// Bad bad bad. But EF/Linq doesn't let us do Includes when using subqueries... Go figure
foreach (var location in locations)
{
location.Checkins = AutoMapper.
Mapper.
Map<List <Checkin>, List<LocationCheckinsJsonViewModel>>
(checkinRepository.GetCheckinsForLocation(location.Id).ToList());
}
// AutoMapper.Mapper.Map<Checkin, CheckinViewModel>(dbCheckin);
var jsonBuilder = new JsonResponseBuilder();
jsonBuilder.AddObject2Response("locations", locations);
return jsonBuilder.JsonEnvelope;
}
现在代码闻起来真的很怪。理想情况下,我希望能够使用GetAllIncluding(c=>c.Checkins)
而不是GetAll
方法,并且能够使用AutoMapper
在LINQ投影内进行映射
我知道使用子查询时,Include+LINQ/EF是按设计返回null的。在LINQ/EF查询中使用automapper应该通过Project().To
完成,但在使用.ForMember
时,这不起作用
因此,挑战在于提高代码的效率(减少SQL并在需要更改JSON结构时易于维护。请记住,我们在这里试图击败node.js/MongoDB;)我应该费心还是保持原样?我使用存储库模式做了类似的事情
public IEnumerable<T> FindAll()
{
return _context.Set<T>().ToList();
}
public IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
{
return _context.Set<T>().Where(predicate);
}
public IEnumerable FindAll()
{
返回_context.Set().ToList();
}
公共IEnumerable FindBy(表达式谓词)
{
返回_context.Set().Where(谓词);
}
其中.Set方法是
public IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
public IDbSet(),其中tenty:class
{
返回base.Set();
}
这允许您从数据库中获取某个类型的所有内容,或者仅获取满足特定条件的所有类型
这就留下了一个对象列表,或者如果使用FirstOrDefault(),则可以根据需要映射单个对象。三件事
System.Data.Entity
命名空间。include
方法实际上是该名称空间引入的扩展。更可取的做法是使用在EF4.1及更高版本中可用的Lambda重载,因此,您必须在想要调用它的任何地方添加名称空间using System.Data.Entity
public IQueryable<LocationEntity> GetAll
{
get
{
return _context.Locations;
}
}
使用System.Data.Entity
公共iqueryablegetall
{
得到
{
返回上下文位置;
}
}
Context context=new Context();
Public List<LocationEntity> GetAll()
{
return context.LocationEntities.Include("includeProperty").ToList();
}
Context Context=newcontext();
公共列表GetAll()
{
返回context.LocationEntities.Include(“includeProperty”).ToList();
}
背景是:
public class Context: DbContext
{
public Context()
{
base.Configuration.LazyLoadingEnabled = false;
base.Configuration.ProxyCreationEnabled = false;
base.Configuration.ValidateOnSaveEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<LocationEntity> LocationEntities{ get; set; }
}
公共类上下文:DbContext
{
公共上下文()
{
base.Configuration.LazyLoadingEnabled=false;
base.Configuration.ProxyCreationEnabled=false;
base.Configuration.ValidateOnSaveEnabled=false;
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Conventions.Remove();
}
公共数据库集位置实体{get;set;}
}
我不知道问题出在哪里。如果在select语句中的位置EntityRepository之后添加。Include(“Checkins”)
。GetAll
EF不允许吗?(其中“Checkins”是实体上导航属性的名称)我必须承认我更喜欢基于方法的Linq语句,并且没有/不能测试上面的代码。但乍一看,这似乎是一个语法问题。但即使没有,您也可以编写请求的“GetAllIncluding()”方法,我认为这不是正确的方法。如果我误解了,请编辑您的问题,将两个实体模型的代码包括在内。#1可以,但不能解决根本问题-它只是语法上的问题#2,命名空间问题将在编译时出现,与此无关,因为上面的示例已经编译#3、ToList()并不违背包含的目的。它将执行包含子实体或集合的查询。您是对的。更改为DbSet甚至会将您的实现与实体框架联系起来,而实体框架并非在所有情况下都是理想的。
public class Context: DbContext
{
public Context()
{
base.Configuration.LazyLoadingEnabled = false;
base.Configuration.ProxyCreationEnabled = false;
base.Configuration.ValidateOnSaveEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<LocationEntity> LocationEntities{ get; set; }
}