用EF已经有段时间了,一般都是和sql server搭配使用,开发效率确实不错,闲来无事,就整了套ef+mysql玩玩,ef+mysql与ef+sql server差异仍是挺大的,下面就说说我遇到的坑,node
我在模型层没有引入EF,故没办法使用EF的特性为个人字段作约束,这也是我指望的结果,我但愿模型层应该和数据库无关。模型定义完执行mysql
1,启用数据迁移:Enable-Migrations,会自动生成一个Migrations/Configuration.cs文件,自动迁移默认为false
2,增长数据迁移项: Add-Migration record,会自动生成数据库建表脚本,
3,执行数据库更新: update-database,自动生成数据库表结构git
外键约束
EF添加外键约束比较特殊,在domain层实体结构中,咱们定义一个用户角色实体,github
public Guid? user_id { get; set; }web
public Guid? role_id { get; set; }sql
public User user { get; set; }数据库
public Role role { get; set; }编程
注意事项c#
user_id 和role_id必须为可空字段,若是不是可空字段,数据库会生成 user_id,user_id_id,role_id,role_id_id。实体关系映射api
public class UserRoleMapper: EntityTypeConfiguration<UserRole>
{
public UserRoleMapper()
{
HasKey(d => d.id);
HasOptional(p => p.user).WithMany(p => p.User_role).HasForeignKey(p => p.user_id).WillCascadeOnDelete(false);
HasOptional(p => p.role).WithMany(p => p.Role_user).HasForeignKey(p => p.role_id).WillCascadeOnDelete(false);
}
}
注意事项
一般咱们开发的会定义一个基类BaseDbContext,实现表的增删查改,在定义一个MainBCUnitOfWork类去集成BaseDbContext,这样 Enable-Migrations命令在多个Dbcontext时候会报错,须要指定为哪个Dbcontext执行数据迁移,具体解决方法是:Enable-Migrations -ContextTypeName MainBCUnitOfWork
这里简单介绍了ef+mysql遇到的坑,若是您的程序可以正常运行,咱们接着往下说GraphQL,
关于什么是GraphQL,小白能够去百度一下,这里假设读者对此有必定的认识,咱们须要引用GraphQL.Net,源码地址是https://github.com/ckimes89/graphql-net,nuget直接搜索GraphQL.Net,安装。在Repository层建立用于查询的 首先定义IGraphQlRepository接口,
public interface IGraphQlRepository: IRepository<Entity>
{
IDictionary<string, object> List(string query);
}
再建立GraphQlRepository类实现IGraphQlRepository接口
public class GraphQlRepository: Repository<Entity>, IGraphQlRepository
{
private GraphQL<MainBCUnitOfWork> gql ;
public GraphQlRepository(MainBCUnitOfWork unitOfWork) : base(unitOfWork)
{
InitGraphQL();
}
private void InitGraphQL()
{
LoggerFactory.GetInstance().Info("create graphql start");
var schema = GraphQL<MainBCUnitOfWork>.CreateDefaultSchema(() => UnitOfWork as MainBCUnitOfWork);
schema.AddScalar(new { year = 0, month = 0, day = 0 }, ymd => new DateTime(ymd.year, ymd.month, ymd.day));
var user = schema.AddType<User>();
user.AddField(u => u.id);
user.AddField(u => u.name);
user.AddField(u => u.nick);
user.AddField(u => u.phone);
user.AddField(u => u.email);
user.AddField(u => u.User_role);
user.AddField("total", (db, u) => db.User.Count());
user.AddField("user_role_id", (db, u) => u.User_role.FirstOrDefault().role_id);
var user_role = schema.AddType<UserRole>();
user_role.AddField(u => u.id);
user_role.AddField(u => u.role);
user_role.AddField(u => u.role_id);
user_role.AddField(u => u.role);
var role = schema.AddType<Role>();
role.AddField(u => u.id);
role.AddField(u => u.name);
role.AddField(u => u.Role_action);
var roleAction = schema.AddType<RoleAction>();
roleAction.AddField(u => u.id);
roleAction.AddField(u => u.action_type);
roleAction.AddField(u => u.navigation);
var navigation = schema.AddType<Navigation>();
navigation.AddField(u => u.id);
navigation.AddField(u => u.action_type);
navigation.AddField(u => u.is_sys);
navigation.AddField(u => u.name);
navigation.AddField(u => u.title);
schema.AddListField("user_roles", db => db.User_role);
//schema.AddListField("users", db => db.User);
schema.AddField("user", new { id = Guid.Empty}, (db, args) => db.User.FirstOrDefault(u => u.id == args.id));
schema.AddListField("users", new { id = Guid.Empty, name = string.Empty }, (db, args) => db.User.AsQueryable().Where(u => u.id == args.id||u.name== args.name));
schema.AddListField("usersByGuid", new { guid = Guid.Empty },
(db, args) => db.User.AsQueryable().Where(a => a.id == args.guid));
schema.Complete();
gql = new GraphQL<MainBCUnitOfWork>(schema);
LoggerFactory.GetInstance().Info("create graphql end "+ gql.GetHashCode());
}
public IDictionary<string, object> List(string query)
{
// var results = gql.ExecuteQuery("{ user(id:\"3c263730-34aa-4927-b78c-1f9da348980f\") { id, name,nick,user_role {id,role_id} } }");
var results = gql.ExecuteQuery(query);
return results;
}
}
在构造器中初始化schema,每次查询都须要经过schema定义的属性组合sql语句,此段初始化代码本想放到静态变量中,这样不用每次查询都要初始化schema,可是GraphQL在每次完成查询以后DbContext会被销毁,此时执行gql.ExecuteQuery会抛出异常,构造器中初始化schema总给人一种不舒服的感受,等找到更好的办法再说吧。
定义IGraphQlAppService接口
public interface IGraphQlAppService
{
IDictionary<string, object> List(string query);
}
定义GraphQlAppService实现该接口
public class GraphQlAppService : IGraphQlAppService
{
private readonly IGraphQlRepository graphQlRepository;
public GraphQlAppService(IGraphQlRepository _graphQlRepository)
{
graphQlRepository = _graphQlRepository;
}
public IDictionary<string, object> List(string query)
{
return graphQlRepository.List(query);
}
}
我用的是微软的Unity容器,
container.RegisterType<IGraphQlAppService, GraphQlAppService>();
container.RegisterType<IGraphQlRepository, GraphQlRepository>();
OK,完成注册。
我用的是webapi实现先后台数据的交互,webapi来作GraphQL!对,没看错,好别扭的感受,好吧,谁让这是个人第一个GraphQL呢,
新建一个webapi控制器,
[Route("Api/V3/List")]
[HttpGet]
public JObject List()
{
var graphQlAppService = IoCFactory.Instance.CurrentContainer.Resolve<IGraphQlAppService>();
var query = HttpContext.Current.Request["query"].ToString();
var results = graphQlAppService.List(query);
var actual = JObject.FromObject(results, Serializer);
return actual;
}
此时一个简单的GraphQL写完,下面看怎么调用
url=http://192.168.5.153:9001/Api/V3/List?query={ user(id:"3c263730-34aa-4927-b78c-1f9da348980f") { id, name,nick,phone,user_role_id,} }
查询id="3c263730-34aa-4927-b78c-1f9da348980f" 的用户id, name,nick,phone,user_role_id信息。
此时去掉user_role_id
url=http://192.168.5.153:9001/Api/V3/List?query={user(id:"3c263730-34aa-4927-b78c-1f9da348980f") { id, name,nick,phone} }
这样就很神奇了,经过统一的查询入口,获得不一样的结果值,是否是有点颠覆rest风格api。接着看
这个查询结果的url=http://192.168.5.153:9001/Api/V3/List?query={ user(id:"3c263730-34aa-4927-b78c-1f9da348980f"){id,name,nick,phone,user_role_id,user_role {id,role_id,role{id,name,role_action{action_type,navigation{action_type,name,title}}}} } }
经过自定义query参数实现了按需查找结果,至此一个完整的GraphQL的demo已经成型,这种获取数据的方式至关前卫,但却不必定是最好的方式,好比如何管理权限,与EF的紧密耦合会致使领域模型暴露出去。配合node实现轻量级的数据访问网关确实是一个很不错的选择,但用到c#实现起来未免有些怪异。GraphQL为咱们提供了一种很友好,灵活的数据交互方式,感受这是将来编程的一个趋势。
总结:
我的比较欣赏用nodejs去作数据网关(单纯的存取数据),GraphQL看上去是一个不错的选择,可是没有作过性能测试,不太清楚高并发会对数据库有和影响,下一步准备用c#简单作个性能测试。本篇文章仅仅是对GraohQL的一种探索,不敢断言其应用场景。文章有不对的地方,欢迎指正。