我有一个包含Web API OData服务层的多租户应用程序.我有一个新的要求来支持自定义字段,这对每个租户都是唯一的,并且在我的表中添加通用的"customfield01","customfield02"列不够灵活.
我已经探索了许多方法来描述和保留后端的自定义数据,但更具挑战性的部分似乎是扩展我的odata服务,以不同的方式为每个租户包含自定义字段.
以下链接使用Web API描述odata v4中的"打开类型":
示例代码工作正常,并提供我的实体所需的动态属性行为.但是,代码只能使用后端的硬编码值列表.如何从实体框架数据上下文填充实体一点也不清楚.
起初,对于每个租户来说,似乎可能就像在数据库中拥有特定于租户的视图一样容易,但问题是扩展属性确实需要从列中"不显示"到键值对.因此,我想知道我是否需要一个单独的实体用于"扩展"属性.所以,我可以为我的POCO提供类似的东西:
public class Item
{
[Key]
public Guid ItemId { get; set; }
public Guid TenantId { get; set; }
// navigation property for the extension entity
public virtual ItemExtension ItemExtension { get; set; }
}
public class ItemExtension
{
[Key]
public Guid ItemId { get; set; }
// dynamic properties for the open type
public IDictionary<string, object> DynamicProperties { get; set; }}
}
Run Code Online (Sandbox Code Playgroud)
但同样,问题变成了如何用我的数据上下文中的数据填充这些对象.再一次,我认为我可以有一个视图来取消列,但这不起作用,因为我可以为每个动态属性提供不同的数据类型(对我来说很重要).
所以,我真的有几个问题:
就我所尝试的而言 …
我有一个使用OData v4的Web Api 2.2项目.正常的EntitySet配置可以根据需要使用所有http谓词.我遇到问题的地方是尝试公开自定义函数.我开始尝试做一些不同于标准示例的事情,但我一直支持尝试使基本示例函数正常工作.
这是我的启动配置(直接来自MS示例):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
namespace Test.Service
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// other entitysets that don't have functions
builder.EntitySet<Product>("Products");
builder.Namespace = "ProductService";
builder.EntityType<Product>().Collection
.Function("MostExpensive")
.Returns<double>();
config.MapODataServiceRoute(
"odataroute"
, "odata"
, builder.GetEdmModel()
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的控制器:
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace Test.Service.Controllers
{
public class ProductsController : ODataController
{
private …Run Code Online (Sandbox Code Playgroud) 我正在阅读和处理大量的Sql Server数据(数百万行中有10行,100多万行+行).在每个源行上执行的处理很重要.单线程版本没有达到预期效果.我目前的并行处理版本在一些较小的批次(300,000个源行,1M个输出行)上表现非常好,但是我遇到了一些非常大的运行的Out of Memory异常.
代码受到了这里提供的答案的启发: 有没有办法将任务并行库(TPL)与SQLDataReader一起使用?
这是一般的想法:
获取源数据(数据太大而无法读入内存,因此我们将"流式传输")
public static IEnumerable<MyObject> ReadData()
{
using (SqlConnection con = new SqlConnection(Settings.ConnectionString))
using (SqlCommand cmd = new SqlCommand(selectionSql, con))
{
con.Open();
using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (dr.Read())
{
// make some decisions here – 1 to n source rows are used
// to create an instance of MyObject
yield return new MyObject(some parameters);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
一旦我们到达并行处理点,我们希望使用SqlBulkCopy对象来写入数据.因此,我们不希望并行处理单个MyObjects,因为我们希望每个线程执行批量复制.因此,我们将从上面读取另一个返回"批量"MyObjects的IEnumerable
class MyObjectBatch
{
public List<MyObject> Items { get; set; }
public MyObjectBatch (List<MyObject> …Run Code Online (Sandbox Code Playgroud) 我有一个由邻接列表描述的层次结构.没有一个根元素,但我确实有数据来识别层次结构中的叶子(终端)项目.所以,一个看起来像这样的层次......
1
- 2
- - 4
- - - 7
- 3
- - 5
- - 6
8
- 9
Run Code Online (Sandbox Code Playgroud)
......将用表格来描述,就像这样. 注意:我无法更改此格式.
id parentid isleaf
--- -------- ------
1 null 0
2 1 0
3 1 0
4 2 0
5 3 1
6 3 1
7 4 1
8 null 0
9 8 1
Run Code Online (Sandbox Code Playgroud)
这是示例表定义和数据:
CREATE TABLE [dbo].[HiearchyTest](
[id] [int] NOT NULL,
[parentid] [int] NULL,
[isleaf] [bit] NOT NULL
)
GO
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) …Run Code Online (Sandbox Code Playgroud) sql sql-server common-table-expression hierarchical-data sql-server-2014
Azure Function 文档清楚地说明了如何使用主机和/或功能密钥来提供“api 密钥”授权。但是,我找不到任何指示在特定功能或功能应用程序上可以创建的键数量是否有限制的信息。
我想与多租户应用程序中的每个租户共享一个唯一的密钥,以便我可以针对每个租户更新或撤销它们。但是,只有当我能够生成数百个(或可能数千个)密钥时,这种方法才有效。
任何人都可以确认函数应用程序上可以生成的密钥数量的任何已知限制吗?
我有一个Kendo UI Grid连接到odata CRUD服务(Web API 2.2 OData V4).dataSource配置如下所示 - baseUrl对所有人来说都是相同的,只是HTTP动词更改.
var dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
beforeSend: prepareRequest,
url: baseUrl,
type: "GET",
dataType: "json"
},
update: {
beforeSend: prepareRequest,
url: function (data) {
return baseUrl + "(" + data.CategoryId + ")";
},
type: "PUT",
dataType: "json"
},
create: {
beforeSend: prepareRequest,
url: baseUrl,
type: "POST",
dataType: "json"
},
destroy: {
beforeSend: prepareRequest,
url: function (data) {
return baseUrl + "(" + data.CategoryId + ")";
}, …Run Code Online (Sandbox Code Playgroud)