用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的一種探索,不敢斷言其應用場景。文章有不對的地方,歡迎指正。