diff --git a/NewPlatform.Flexberry.ORM.ODataService.nuspec b/NewPlatform.Flexberry.ORM.ODataService.nuspec
index 40f52d72..3fcf28b3 100644
--- a/NewPlatform.Flexberry.ORM.ODataService.nuspec
+++ b/NewPlatform.Flexberry.ORM.ODataService.nuspec
@@ -1,115 +1,115 @@
-
-
-
- NewPlatform.Flexberry.ORM.ODataService
- 7.2.0-beta02
- Flexberry ORM ODataService
- New Platform Ltd.
- New Platform Ltd.
- http://flexberry.ru/License-FlexberryOrm-Runtime
- https://flexberry.net/ru/developers-flexberry-orm.html
- https://flexberry.net/img/logo-color.png
- true
- Flexberry ORM OData Service Package.
-
- Added
- 1. `updateViews` parameter of `DefaultDataObjectEdmModelBuilder` class. It allows to change update views for data objects (update view is used for loading a data object during OData update requests).
-
- Changed
- 1. Updated Flexberry ORM up to 7.2.0-beta01.
-
- Fixed
- 1. Fixed loading of object with crushing of already loaded masters.
- 2. Fixed loading of details.
-
- Copyright New Platform Ltd 2023
- Flexberry ORM OData ODataService
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ NewPlatform.Flexberry.ORM.ODataService
+ 7.2.0-beta02
+ Flexberry ORM ODataService
+ New Platform Ltd.
+ New Platform Ltd.
+ http://flexberry.ru/License-FlexberryOrm-Runtime
+ https://flexberry.net/ru/developers-flexberry-orm.html
+ https://flexberry.net/img/logo-color.png
+ true
+ Flexberry ORM OData Service Package.
+
+ Added
+ 1. `updateViews` parameter of `DefaultDataObjectEdmModelBuilder` class. It allows to change update views for data objects (update view is used for loading a data object during OData update requests).
+
+ Changed
+ 1. Updated Flexberry ORM up to 7.2.0-beta01.
+
+ Fixed
+ 1. Fixed loading of object with crushing of already loaded masters.
+ 2. Fixed loading of details.
+
+ Copyright New Platform Ltd 2023
+ Flexberry ORM OData ODataService
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NewPlatform.Flexberry.ORM.ODataService/Controllers/DataObjectController.ModifyData.cs b/NewPlatform.Flexberry.ORM.ODataService/Controllers/DataObjectController.ModifyData.cs
index b9bfc550..bc17d0e4 100644
--- a/NewPlatform.Flexberry.ORM.ODataService/Controllers/DataObjectController.ModifyData.cs
+++ b/NewPlatform.Flexberry.ORM.ODataService/Controllers/DataObjectController.ModifyData.cs
@@ -23,13 +23,13 @@ namespace NewPlatform.Flexberry.ORM.ODataService.Controllers
#if NETFRAMEWORK
using System.Net.Http.Formatting;
+ using System.Web;
using System.Web.Http;
using System.Web.Http.Results;
using System.Web.Http.Validation;
+ using Newtonsoft.Json.Linq;
using NewPlatform.Flexberry.ORM.ODataService.Events;
using NewPlatform.Flexberry.ORM.ODataService.Handlers;
- using Newtonsoft.Json.Linq;
- using System.Web;
#endif
#if NETSTANDARD
using Microsoft.AspNet.OData.Formatter;
@@ -860,6 +860,11 @@ private static void AddObjectToUpdate(List objsToUpdate, DataObject
/// Значение ключа.
private object GetKey(EdmEntityObject edmEntity)
{
+ if (edmEntity == null)
+ {
+ throw new ArgumentNullException(nameof(value), $"{nameof(edmEntity)} can not be null.");
+ }
+
object key;
// Получим значение ключа.
@@ -878,6 +883,11 @@ private object GetKey(EdmEntityObject edmEntity)
/// Объект данных.
private DataObject GetDataObjectByEdmEntityLight(EdmEntityObject edmEntity)
{
+ if (edmEntity == null)
+ {
+ throw new ArgumentNullException(nameof(value), $"{nameof(edmEntity)} can not be null.");
+ }
+
var masterType = _model.GetDataObjectType(edmEntity);
var masterKey = GetKey(edmEntity);
var dataObject = (DataObject)Activator.CreateInstance(masterType);
diff --git a/NewPlatform.Flexberry.ORM.ODataService/Extensions/DataServiceExtensions.cs b/NewPlatform.Flexberry.ORM.ODataService/Extensions/DataServiceExtensions.cs
index 427dbf86..a299aa6c 100644
--- a/NewPlatform.Flexberry.ORM.ODataService/Extensions/DataServiceExtensions.cs
+++ b/NewPlatform.Flexberry.ORM.ODataService/Extensions/DataServiceExtensions.cs
@@ -1,419 +1,419 @@
-namespace NewPlatform.Flexberry.ORM.ODataService.Extensions
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
-
- using ICSSoft.STORMNET;
- using ICSSoft.STORMNET.Business;
- using ICSSoft.STORMNET.Business.LINQProvider;
- using ICSSoft.STORMNET.FunctionalLanguage;
- using ICSSoft.STORMNET.FunctionalLanguage.SQLWhere;
-
- ///
- /// Класс, содержащий расширения для сервиса данных.
- ///
- public static class DataServiceExtensions
- {
- ///
- /// Осуществляет вычитку объектов данных заданного типа по заданному представлению и LINQ-выражению.
- ///
- /// Экземпляр сервиса данных.
- /// Тип вычитываемых объектов данных, наследуемый от .
- /// Представления для вычитки объектов данных.
- /// LINQ-выражение, ограничивающее набор вычитываемых объектов.
- /// Коллекция вычитанных объектов.
- public static object Execute(this SQLDataService dataService, Type dataObjectType, View dataObjectView, Expression expression)
- {
- IQueryProvider queryProvider = typeof(LcsQueryProvider<,>)
- .MakeGenericType(dataObjectType, typeof(LcsGeneratorQueryModelVisitor))
- .GetConstructor(new Type[3] { typeof(SQLDataService), typeof(View), typeof(IEnumerable) })
- .Invoke(new object[3] { dataService, dataObjectView, null }) as IQueryProvider;
-
- return queryProvider.Execute(expression);
- }
-
- ///
- /// Загрузка объекта с его мастерами (объект должен быть не изменнённый и не до конца загруженный).
- /// С мастерами необходимо обращаться аккуратно: если в кэше уже есть мастер, то нужно эту ситуацию разрешить,
- /// поскольку иначе стандартная загрузка перетрёт данные мастера в кэше (и если он там изменён, то все изменения будут потеряны).
- ///
- /// Экземпляр сервиса данных.
- /// Представление объекта с мастерами.
- /// Объект данных, в который будет производиться загрузка.
- /// Текущий кэш объектов данных (в данном кэше ранее существующие там объекты не должны быть перетёрты).
- public static void SafeLoadWithMasters(
- this IDataService dataService, View view, ICSSoft.STORMNET.DataObject dobjectFromCache, DataObjectCache dataObjectCache)
- {
- if (dataService == null)
- {
- throw new ArgumentNullException(nameof(dataService));
- }
-
- if (view == null)
- {
- throw new ArgumentNullException(nameof(view));
- }
-
- if (dobjectFromCache == null)
- {
- throw new ArgumentNullException(nameof(dobjectFromCache));
- }
-
- if (dataObjectCache == null)
- {
- throw new ArgumentNullException(nameof(dataObjectCache));
- }
-
- // Прогружается пустой объект, чтобы избежать риска перетирания основного.
- DataObject createdObject = (DataObject)Activator.CreateInstance(dobjectFromCache.GetType());
- createdObject.SetExistObjectPrimaryKey(dobjectFromCache.__PrimaryKey);
-
- // Используется отдельный кэш, чтобы не перетереть данные в основном кэше.
- DataObjectCache specialCache = new DataObjectCache();
- specialCache.StartCaching(false);
- specialCache.AddDataObject(createdObject);
- dataService.LoadObject(view, createdObject, false, true, specialCache);
- specialCache.StopCaching();
-
- // Перенос данных из одного объекта в другой.
- ProperUpdateOfObject(dobjectFromCache, createdObject, dataObjectCache, specialCache);
- }
-
- ///
- /// Загрузка детейлов с сохранением состояния изменения.
- ///
- /// Экземпляр сервиса данных.
- /// Представление агрегатора с детейлами. Чтение будет идти по массиву Details представлений детейлов, включая детейлы второго и последующих уровней.
- /// Агрегаторы, для которых дочитываются детейлы.
- /// Кеш объектов данных, в нём хранятся состояния детейлов, которые не надо затирать. В него же будут добавлены новые зачитанные детейлы.
- public static void SafeLoadDetails(this IDataService dataService, View view, IList agregators, DataObjectCache dataObjectCache)
- {
- if (dataService == null)
- {
- throw new ArgumentNullException(nameof(dataService));
- }
-
- if (view == null)
- {
- throw new ArgumentNullException(nameof(view));
- }
-
- if (agregators == null)
- {
- throw new ArgumentNullException(nameof(agregators));
- }
-
- if (dataObjectCache == null)
- {
- throw new ArgumentNullException(nameof(dataObjectCache));
- }
-
- if (agregators.Count == 0)
- {
- return;
- }
-
- // Обрабатываем все детейлы, которые указаны в представлении.
- DetailInView[] detailsInView = view.Details;
- foreach (DetailInView detailInView in detailsInView)
- {
- // Оригинальное представление будет использоваться в рекурсии.
- View detailView = detailInView.View.Clone();
- DetailInView[] secondDetailsInView = detailView.Details;
-
- // Удалим из представления детейлы второго уровня, поскольку их обработка будет рекурсивной с аналогичной логикой.
- foreach (DetailInView secondDetailInView in secondDetailsInView)
- {
- detailView.RemoveDetail(secondDetailInView.Name);
- }
-
- Type detailType = detailView.DefineClassType;
- string agregatorPropertyName = Information.GetAgregatePropertyName(detailType);
-
- // Нужно гарантировать, что у загруженных детейлов будет проставлена ссылка на агрегатора, поэтому добавим свойство в представление (если уже есть, то второй раз не добавится).
- detailView.AddProperty(agregatorPropertyName);
- LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(detailView.DefineClassType, detailView);
- Type[] usageTypes = TypeUsageProvider.TypeUsage.GetUsageTypes(view.DefineClassType, detailInView.Name);
- List storedTypes = new List();
- foreach (var usageType in usageTypes)
- {
- if (Information.IsStoredType(usageType))
- {
- storedTypes.Add(usageType);
- }
- }
-
- if (!storedTypes.Any())
- {
- foreach (DataObject agregator in agregators)
- {
- Type agregatorType = agregator.GetType();
- Type[] usageTypesFromAgregator = TypeUsageProvider.TypeUsage.GetUsageTypes(agregatorType, detailInView.Name);
- foreach (Type usageTypeFromAgregator in usageTypesFromAgregator)
- {
- if (Information.IsStoredType(usageTypeFromAgregator) && !storedTypes.Contains(usageTypeFromAgregator))
- {
- storedTypes.Add(usageTypeFromAgregator);
- }
- }
- }
- }
-
- lcs.LoadingTypes = storedTypes.ToArray();
- Type agregatorKeyType = agregators[0].__PrimaryKey.GetType();
-
- // Производим обработку только тех агрегаторов, для которых ранее не был загружен детейл.
- object[] keys = agregators.Where(a => !a.CheckLoadedProperty(detailInView.Name)).Select(d => d.__PrimaryKey).ToArray();
- lcs.LimitFunction = FunctionBuilder.BuildIn(agregatorPropertyName, SQLWhereLanguageDef.LanguageDef.GetObjectTypeForNetType(agregatorKeyType), keys);
-
- // Нужно соблюсти единственность инстанций агрегаторов при вычитке, поэтому реализуем отдельный кеш. Смешивать с кешем dataObjectCache нельзя, поскольку в предстоящей выборке будут те же самые детейлы (значения в кеше затрутся).
- // Агрегаторы в кэш не помещаем. От помещения агрегаторов в кэш возникают неконтролируемые сбои основного кэша.
- DataObjectCache agregatorCache = new DataObjectCache();
- agregatorCache.StartCaching(false);
-
- // Вычитываются детейлы одного типа, но для нескольких инстанций агрегаторов (оптимизируем количество SQL-запросов).
- DataObject[] loadedDetails = dataService.LoadObjects(lcs, agregatorCache);
- agregatorCache.StopCaching();
-
- Dictionary