Power Apps 学习笔记 - IOrganizationService Interface

1. IOrganization Interface

1.1 基本介绍

  1. IOrganization 是用于向组织提供元数据以及数据的编程访问的接口. (Dataverse的增删改查以及表联系的相关操作)
//ServiceClient、CrmServiceClient 都可实现 IOrganizationService接口
IOrganizationService service = new CrmServiceClient(connectionString);
IOrganizationService service = new ServiceClient(connectionString);
using Microsoft.Crm.Sdk.Messages;
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk;

class Program
{
    // Dataverse环境URL以及登录信息
   static string url = "https://yourorg.crm.dynamics.com";
   static string userName = "you@yourorg.onmicrosoft.com";
   static string password = "yourPassword";

    // 连接上述代码串进行测试
    static string connectionString = $@"
    AuthType = OAuth;
    Url = {url};
    UserName = {userName};
    Password = {password};
    AppId = 51f81489-12ee-4a9e-aaae-a2591f45987d;
    RedirectUri = http://localhost;
    LoginPrompt=Auto;
    RequireNewInstance = True";

    static void Main()
    {
        // 获取IorganizationService的接口实例
        IOrganizationService service = new ServiceClient(connectionString);

        var response = (WhoAmIResponse)service.Execute(new WhoAmIRequest());
        Console.WriteLine($"User ID is {response.UserId}.");

        // Pause the console so it does not close.
        Console.WriteLine("Press the <Enter> key to exit.");
        Console.ReadLine();
    }
}

  参考文献. c#连接Microsoft Dataver:c#连接 MicroSoft Dataverse

1.2 方法分析

在这里插入图片描述
  参考文献. IOrganization:IOrganizationService 接口

2. 其他对象

2.1 Entity

  简介:

在这里插入代码片

2.2 EntityReference

  简介: 实体引用,当在表字段当中设置了一对一或者一对多等关系时,其关联的查询列的赋值或者修改必须使用这个 EntityReference 类完成.

## Constructors
EntityReference()
EntityReference(String)
EntityReference(String, Guid)
EntityReference(String, KeyAttributeCollection)
EntityReference(String, String, Object)

## Example
// 房间的逻辑名 crda9_room + 唯一表示符 Guid
order["crda9_room"] = new EntityReference("crda9_room", new Guid("43c1ebcb-b7ae-ee11-a569-000d3a85d072"));

2.3 OptionSetValue

  简介: 单选列,当在表字段当中设置了选择列的时候,其值必须使用 OptionSetValue 设置其值

## Constructors
OptionSetValue()
OptionSetValue(int value)

## Example
// 订单的单选列crda9_site = 1
order["crda9_site"] = new OptionSetValue(1);

  参考文献. Entity对象:Entity对象

2.4 AliasedValue

  简介: 别名列,当对属性值取别名后,使用该类获取值.

## Constructors
AliasedValue()

## Example
QueryExpression query = new QueryExpression("crda9_order");
query.ColumnSet.AddColumns("crda9_orderid"); // 原表的相关查找的列
LinkEntity linkEntity = new LinkEntity("crda9_order", "crda9_room", "crda9_room", "crda9_roomid", JoinOperator.Inner);
linkEntity.Columns.AddColumns("crda9_name", "crda9_site"); // 关联表的属性名称
linkEntity.EntityAlias = "hello"; // 关联表的别名
query.LinkEntities.Add(linkEntity);

EntityCollection ec = service.RetrieveMultiple(query);
AliasedValue ax = ec[0].GetAttributeValue<AliasedValue>("hello.crda9_name");

3. 相关方法

3.1 单行查询 Retrive

  a. 代码及使用

//public Microsoft::Xrm::Sdk::Entity ^ Retrieve(System::String ^ entityName, Guid id, Microsoft::Xrm::Sdk::Query::ColumnSet ^ columnSet);    
static void Retrive(IOrganizationService service){
    string entityName = "crda9_room"; // 逻辑名称
    ColumnSet columnSet = new ColumnSet("crda9_name", "crda9_type", "crda9_site"); // 查询的属性
    Guid guid = new Guid("4e4c81a1-439d-ee11-be37-000d3a85d073"); // 全局唯一标识符

    Entity entity = service.Retrieve(entityName, guid, columnSet); // 发起查询
    Console.WriteLine($"name:{entity.GetAttributeValue<string>("crda9_name")}"
        + "   " + $"type:{entity.GetAttributeValue<OptionSetValue>("crda9_type").Value}"
        + "   " + $"site:{entity.GetAttributeValue<string>("crda9_site")}");
}

3.2 多行查询 RetriveMultiple

  a. 代码及使用

// Microsoft::Xrm::Sdk::EntityCollection ^ RetrieveMultiple(Microsoft::Xrm::Sdk::Query::QueryBase ^ query);
static void RetriveMultiple(IOrganizationService service){
    QueryExpression query = new("crda9_room") { }; // 表逻辑名称
    query.ColumnSet.AddColumns("crda9_name"); // 查询字段
    EntityCollection results = service.RetrieveMultiple(query); // 查询发送

    foreach (Entity entity in results.Entities){
        Console.WriteLine($"Id:{entity.Id}"); // 全局唯一标识符(每行数据有一个Id)
        Console.WriteLine($"name:{entity.Attributes["crda9_name"]}");
    }
    if(result?.Entities?.Count > 0){ // 提倡
		// 利用了c#当中的空值判断运算符,当为空时会直接返回 false 跳过本次程序执行
	}
}

  b. QueryExpression 总结

public ref class QueryExpression sealed : Microsoft::Xrm::Sdk::Query::QueryBase
query.EntityName = "crda9_room"; // 1.EntityName --> 表逻辑名(可在构造函数时直接构造)
query.ColumnSet.AddColumns("crda9_name"); // 2.ColumnSet --> 负责查询列数
query.ColumnSet = new ColumnSet(true); // 默认查询所有字段(默认情况只会查询唯一标识符Id)
query.Criteria.AddCondition("crda9_type", ConditionOperator.Equal, 0); // 3.Criteria --> 查询限定条件
query.AddOrder("crda9_name", OrderType.Ascending); // 4. AddOrder --> 列排序
query.TopCount = 2; // 5. TopCount --> 控制显示的行数(与PageInfo不能同时使用)
query.PageInfo = new PagingInfo() {  // 6. PageInfor --> 控制分页
    PageNumber = 1, // 页数
    Count = 2, // 每页数量
    PagingCookie = null // 缓存大量数据集查询时的首尾记录信息,避免查询重复记录,提高效率
};

  c. 大量数据查询(> 5000条,系统默认每次最多查询5000条)

EntityCollection result = new EntityCollection();
int pageNum = 1;
int pageSize = 5000;
while(true) {
    query.PageInfo = new PagingInfo {
        Count = pageSize,
        PageNumber = pageNum,
        PagingCookie = pageNum == 1 ? null : result.PagingCookie
    };
    pageNum ++;
    EntityCollection pageResult = service.RetrieveMultiple(query);
    result.Entities.AddRange(pageResult.Entities);
    result.PagingCookie = pageResult.PagingCookie; // 缓存查询集首尾记录, 提高查询效率
    if(!pageResult.MoreRecords) { //没有更多记录就跳出循环
        break;
    }
}

3.3 增加 Create

  a. 代码及使用

// Guid Create(Microsoft::Xrm::Sdk::Entity ^ entity);
static void CreateExpressionExample(IOrganizationService service)
{
    Entity entity = new Entity("crda9_student");
    entity["crda9_name"] = "新学生_张雪雪";
    entity["crda9_age"] = 17;
    
    // entity.Id = Guid.NewGuid(); 可以随机生成Id, 基本上不会重复
    
    Guid id = service.Create(entity); 
    Console.WriteLine("新学生的唯一id为:" + id);
}

3.4 删除 Delete

  a. 代码及使用

//  void Delete(System::String ^ entityName, Guid id);
static void DeleteExpressionExample(IOrganizationService service)
{
    string entityName = "crda9_student"; // 逻辑名称
    Guid guid = new Guid("e334ba87-4c9a-ee11-be37-000d3a85d073"); // 全局唯一标识符

    service.Delete(entityName, guid); 
}

3.5 修改 Update

  a. 代码及使用

// void Update(Microsoft::Xrm::Sdk::Entity ^ entity);
    static void UpdateExpressionExample(IOrganizationService service)
    {
        Guid id = CreateExpressionExample(service); // 先调用函数创建一个新学生,返回其Id唯一标识

        Entity entity = new Entity("crda9_student");
        entity.Id = id;
        entity["crda9_name"] = "更新后的学生";

        service.Update(entity);
        Console.WriteLine("successful update....");
    }


4. 数据查询的不同实现方式

  QueryBase的实现类
在这里插入图片描述
  参考文献. QueryBase抽象类接口:QueryBase抽象类接口

4.1 QueryExpression

  QueryExpression类 – 属性
在这里插入图片描述

  1. QueryExpression 是较为常用的数据查询类,支持列查询、条件判断、实体联系、排序等操作,
  2. 示例代码见相关方法当中多行查询

  QueryExpression类:QueryExpression类

4.1.1 LinkEntities
  1. public:LinkEntity(linkFromEntityName, linkToEntityName, linkFromAttributeName, linkToAttributeName, JoinOperator joinOperator);
  2. 字段解析
    linkFromEntityName: 原表逻辑名
    linkToEntityName: 关联表逻辑名
    linkFromAttributeName:原表(查找列字段逻辑名)
    linkToAttributeName:关联表唯一逻辑名
  3. 补充
    可以将原表逻辑名和关联表逻辑名位置对换,其原表查找列linkFromAttributeName和关联表唯一逻辑名linkToAttributeName的位置也相应兑换即可
// 样例A: 每个 crda9_order 对应一个 crda9_room, 查找列在 crda9_order 上
IOrganizationService service = new ServiceClient(connectionString);

QueryExpression query = new QueryExpression("crda9_order");
query.ColumnSet.AddColumns("crda9_orderid"); // 原表的相关查找的列

LinkEntity linkEntity = new LinkEntity("crda9_order", "crda9_room", "crda9_room", "crda9_roomid", JoinOperator.Inner); 
linkEntity.Columns.AddColumns("crda9_name", "crda9_site"); // 关联表的属性名称
linkEntity.EntityAlias = "hello"; // 关联表的别名
query.LinkEntities.Add(linkEntity);

EntityCollection ec = service.RetrieveMultiple(query);
// 样例B: 每个crda9_room 对应多个crda9_order, 查找列在crda9_order 上, 但是我们从crda9_room上进行查找
IOrganizationService service = new ServiceClient(connectionString);

QueryExpression query = new QueryExpression("crda9_room");
query.ColumnSet.AddColumns("crda9_name"); // 原表的相关查找的列

LinkEntity linkEntity = new LinkEntity("crda9_room", "crda9_order", "crda9_roomid", "crda9_room", JoinOperator.Inner);
linkEntity.Columns.AddColumns("crda9_id"); // 关联表的属性名称
linkEntity.EntityAlias = "hello"; // 关联表的别名
query.LinkEntities.Add(linkEntity);

EntityCollection ec = service.RetrieveMultiple(query);

4.2 JoinOperator.Inner 与 JoinOperator.LeftOuter

JoinOperator.Inner: 内连接(若两个表都有Critera判断,会先将两个表各自筛出来,最后将两张表筛选出来的结果通过匹配行匹配后再返回).
JoinOperator.LeftOuter: 左外连接操作符(两张表先通过Critera筛选各自筛出来,随后左边表内容全部保存,右边若可以匹配则进行匹配连接).

核心:需要连接的表先各自通过Critera筛选自己的表,随后内连接只显示可以匹配的内容(左边内容若未匹配右边表的话左边此条记录可能消失),左外连接(左边筛选后的内容必定保留)
表:
在这里插入图片描述

代码:

static void TestLeftAndInnerSQL(IOrganizationService service)
{
    QueryExpression query = new QueryExpression("crda9_order");
    query.ColumnSet.AddColumns("crda9_id"); // 原表的相关查找的列
    query.Criteria.AddCondition("crda9_site", ConditionOperator.Equal, 1);

    LinkEntity linkEntity = new LinkEntity("crda9_order", "crda9_room", "crda9_room", "crda9_roomid", JoinOperator.Inner);
    linkEntity.Columns.AddColumns("crda9_name"); // 关联表的属性名称
    linkEntity.LinkCriteria.AddCondition("crda9_name", ConditionOperator.Equal, "20");
    linkEntity.EntityAlias = "room"; // 关联表的别名
    query.LinkEntities.Add(linkEntity);

    EntityCollection ec = service.RetrieveMultiple(query);
}

JoinOperator.Inner结果: 筛选后order剩下三个,room剩下一个,但是可以匹配的结果只有一个.在这里插入图片描述
JoinOperator.LeftOuter结果: 筛选后order剩下三个,room剩下一个,可以匹配的会将列多保留一个.
在这里插入图片描述
在这里插入图片描述

4.1.3 Criteria
  1. Criteria属性作为数据过滤的一些标准,其参数是 Microsoft.Xrm.Sdk.Query.FilterExpression class
FilterExpression Class
## 属性Properties
a. Conditions 包含属性值相关的条件表达式(对满足条件的属性值进行过滤)
b. Filters 筛选查询结果和设定逻辑表达式层次结构(类似于表达式当中大括号的作用(), 可以不断内嵌FilterExpression)
c. FilterOperator 连接表达式内部 Condition 的关联,默认是AND
## 细节
这里的Filters当中的过滤器并不是嵌套查询. (s1 AND s2)OR s3, 这里不会先筛选满足s1 AND s2, 再将结果和s3进行处理,而是判断整个表达式
// [new_month] = '3' OR [new_month] = '4' OR [new_year] = '2024'
QueryExpression query = new QueryExpression("xxxxxxxx");
query.ColumnSet = new ColumnSet("new_month", "new_year");
query.Criteria.FilterOperator = LogicalOperator.Or; // 默认AND
query.Criteria.AddCondition("new_year", ConditionOperator.Equal, 2024);
query.Criteria.AddCondition("new_month", ConditionOperator.Equal, 3);
query.Criteria.AddCondition("new_month", ConditionOperator.Equal, 4);
 // ([crda9_month] = '1' OR [crda9_month] = '2') AND [crda9_year] = '2024'.
 QueryExpression query = new QueryExpression("crda9_order");
 query.ColumnSet = new ColumnSet("crda9_year", "crda9_month");
 query.Criteria.FilterOperator = LogicalOperator.And;
 query.Criteria.AddCondition("crda9_year", ConditionOperator.Equal, 2024);

 FilterExpression childFilter = query.Criteria.AddFilter(LogicalOperator.Or);
 childFilter.AddCondition("crda9_month", ConditionOperator.Equal, "1");
 childFilter.AddCondition("crda9_month", ConditionOperator.Equal, "2");
 // [ ([crda9_month] = '1' OR [crda9_month] = '2') AND ([crda9_month] = '2' OR [crda9_month] = '3') ] 
 //  AND [crda9_year] = '2024'.
 QueryExpression query = new QueryExpression("crda9_order");
 query.ColumnSet = new ColumnSet("crda9_year", "crda9_month");
 query.Criteria.AddCondition("crda9_year", ConditionOperator.Equal, 2024);

 FilterExpression childFilter = query.Criteria.AddFilter(LogicalOperator.Or);
 childFilter.AddCondition("crda9_month", ConditionOperator.Equal, "1");
 childFilter.AddCondition("crda9_month", ConditionOperator.Equal, "2");

 FilterExpression childFilter2 = query.Criteria.AddFilter(LogicalOperator.Or);
 childFilter2.AddCondition("crda9_month", ConditionOperator.Equal, "2");
 childFilter2.AddCondition("crda9_month", ConditionOperator.Equal, "3");

4.2 QueryByAttribute

  QueryByAttribute类 – 属性
在这里插入图片描述

  1. 感觉功能可以由QueryByExpression代替,感觉这个可能更加侧重通过属性来查找判断,
	static void QueryByAttributeTest(IOrganizationService service){
	    QueryByAttribute query = new QueryByAttribute("crda9_room") {
	        ColumnSet = new ColumnSet("crda9_name", "crda9_site"),
	    };
	
	    query.AddAttributeValue("crda9_site", "武汉"); // 此行必须实现(查找满足条件的数据)
	
	    EntityCollection results = service.RetrieveMultiple(query);
	    foreach (Entity entity in results.Entities){
	        Console.WriteLine($"name:{entity.Attributes["crda9_name"]}");
	        Console.WriteLine($"site:{entity.Attributes["crda9_site"]}");
	    }
	}

4.3 FetchExpression(FetchXML)

4.3.1 FetchExpression类

在这里插入图片描述

  1. 通过使用Fetch Xml语句拼接完成属性的查询以及过滤判断等相关操作.
  2. Dynamic 365 -> 高级查找 -> Fetch XML 使用
  3. 补充字符串使用
    a. @ 防止转义字符串, 可以省略使用/转义的操作, 单引号需要使用双引号转义. 可多行换行, 会将每行前面空格算入内
    b. $ 插值字符串, 可使用{}插入数据值, 方法类似与代替string.format(“{0}”, 数据值). 不可多行换行
    c. “”“”“” 多行字符串. 可多行换行,其每行最前列以第二个"""的那一列作为标准.
static void QueryByFetch(IOrganizationService service){
    string fetchXml = $@"<fetch version=""1.0"" output-format=""xml-platform"" mapping=""logical"" distinct=""false"">
        <entity name=""crda9_room"">
        <attribute name=""crda9_name"" />
        <attribute name=""crda9_type"" />
        <attribute name=""crda9_site"" />
        <attribute name=""crda9_detail"" />
        <filter type=""and"">
            <condition attribute=""crda9_name"" operator=""like"" value=""%北京%"" />
        </filter>
        </entity>
    </fetch>";

    FetchExpression query = new FetchExpression(fetchXml);
    EntityCollection results = service.RetrieveMultiple(query);
    foreach (Entity entity in results.Entities){
        Console.WriteLine($"name:{entity.Attributes["crda9_name"]}");
        Console.WriteLine($"site:{entity.Attributes["crda9_site"]}");
    }
}
foreach (Entity entity in results.Entities){
    Console.WriteLine($""" 
    name: {entity["crda9_name"]}
    type: {entity.GetAttributeValue<OptionSetValue>("crda9_type")?.Value} // 防止为Null
    site: {entity.GetAttributeValue<OptionSetValue>("crda9_site")?.Value} // 防止为Null
    """);
}

4.3.2 FetchXml 相关功能补充
  • link-entity
## 1. link-entity:
<entity name="account">
  <attribute name="name" />
  <link-entity name="contact"   from="account表当中设置的查找列逻辑名"   to="concat表的唯一列Id" >
    <attribute name="fullname" />
  </link-entity>
</entity>

## 2. 联表查询链接方式:
inner == INNER JOIN(SQL)
outer == LEFT OUTER(SQL)
static void Main() {
    IOrganizationService organizationService = new ServiceClient(connectionString);

    string fetchXml = $@"<fetch version=""1.0"" output-format=""xml-platform"" mapping=""logical"" distinct=""false"">
        <entity name=""crda9_order"">
        <attribute name=""crda9_id"" />
        <link-entity name='crda9_room' from='crda9_roomid' to='crda9_room' link-type='inner' alias='room_'>
            <attribute name='crda9_name' />
            <attribute name='crda9_type' />
            <attribute name='crda9_site' />
            <attribute name='crda9_detail' />
        </link-entity>
        <filter type=""and"">
        <condition attribute=""crda9_id"" operator=""eq"" value=""032"" />
        </filter>
        </entity>
        </fetch>";

        FetchExpression query = new FetchExpression(fetchXml);
        EntityCollection results = organizationService.RetrieveMultiple(query);
        foreach(Entity entity in results.Entities) {
            Console.WriteLine($"id:{entity.Attributes["crda9_id"]}");
            Console.WriteLine($"roomName::{((AliasedValue)entity.Attributes["room_.crda9_name"]).Value}");
            Console.WriteLine($"roomType::{((AliasedValue)entity.Attributes["room_.crda9_type"]).Value}");
            Console.WriteLine($"roomSite::{((AliasedValue)entity.Attributes["room_.crda9_site"]).Value}");
            Console.WriteLine($"roomDetail::{((AliasedValue)entity.Attributes["room_.crda9_detail"]).Value}");
        }
}

/*
id:032
roomName::北京A01会议室
roomType::Microsoft.Xrm.Sdk.OptionSetValue
roomSite::北京
roomDetail::容纳50人
*/

4.4 LINQ

  1. LINQ 最明显的“语言集成”部分就是查询表达式。 查询表达式采用声明性查询语法编写而成。 使用查询语法,可以用最少的代码对数据源执行筛选、排序和分组操作。

5. 细节

5.1 取值前先判断 ---- 对不能赋值为Null的数据先判空.

 Entity entity = new Entity();
 entity["name"] = "zhangsan";
 if(entity.Contains("name")) // 先判断是否包含
 {
     // 使用GetAttribute可以判断键值对当中的键是否存在,但是保险起见最好也需要先Contains判断
     var name = entity.GetAttributeValue<string>("name"); 
 }
// Guid 类型永远不会为Null 
// 也不可以通过 new Guid(null) 初始化
Guid guid = new Guid(); 
if(guid == Guid.Empty)
{
    Console.WriteLine("Guid 的空值比较通过 Guid.Empty 比较");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

psudd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值