12

次のクラスを使用して剣道グリッドをロード/フィルタリング/注文するための最良の方法は何ですか:

ドメイン:

public class Car
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual bool IsActive { get; set; }
}

ビューモデル

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}

オートマッパー

Mapper.CreateMap<Car, CarViewModel>()
      .ForMember(dest => dest.IsActiveText, 
                 src => src.MapFrom(m => m.IsActive ? "Yes" : "No"));

IQueryable

var domainList = RepositoryFactory.GetCarRepository().GetAllQueryable();

DataSourceResult

var dataSourceResult = domainList.ToDataSourceResult<Car, CarViewModel>(request, 
                          domain => Mapper.Map<Car, ViewModel>(domain));

グリッド

...Kendo()
  .Grid<CarViewModel>()
  .Name("gridCars")
  .Columns(columns =>
  {
     columns.Bound(c => c.Name);
     columns.Bound(c => c.IsActiveText);
  })
  .DataSource(dataSource => dataSource
     .Ajax()
     .Read(read => read.Action("ListGrid", "CarsController"))
  )
  .Sortable()
  .Pageable(p => p.PageSizes(true))

OK、グリッドは初めて完全にロードされますが、フィルター/並べ替えをIsActiveText行うと、次のメッセージが表示されます。

無効なプロパティまたはフィールド - タイプの「IsActiveText」: 車

このシナリオでの最善のアプローチは何ですか?

4

6 に答える 6

12

Kendo が "DataSourceRequestAttribute" と "DataSourceRequestModelBinder" を実装した方法は好きではありませんが、それは別の話です。

「フラット化された」オブジェクトである VM プロパティでフィルタリング/ソートできるようにするには、次を試してください。

ドメイン モデル:

public class Administrator
{
    public int Id { get; set; }

    public int UserId { get; set; }

    public virtual User User { get; set; }
}

public class User
{
    public int Id { get; set; }

    public string UserName { get; set; }

    public string Email { get; set; }
}

モデルを見る:

public class AdministratorGridItemViewModel
{
    public int Id { get; set; }

    [Displaye(Name = "E-mail")]
    public string User_Email { get; set; }

    [Display(Name = "Username")]
    public string User_UserName { get; set; }
}

拡張子:

public static class DataSourceRequestExtensions
{
    /// <summary>
    /// Enable flattened properties in the ViewModel to be used in DataSource.
    /// </summary>
    public static void Deflatten(this DataSourceRequest dataSourceRequest)
    {
        foreach (var filterDescriptor in dataSourceRequest.Filters.Cast<FilterDescriptor>())
        {
            filterDescriptor.Member = DeflattenString(filterDescriptor.Member);
        }

        foreach (var sortDescriptor in dataSourceRequest.Sorts)
        {
            sortDescriptor.Member = DeflattenString(sortDescriptor.Member);
        }
    }

    private static string DeflattenString(string source)
    {
        return source.Replace('_', '.');
    }
}

属性:

[AttributeUsage(AttributeTargets.Method)]
public class KendoGridAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        foreach (var sataSourceRequest in filterContext.ActionParameters.Values.Where(x => x is DataSourceRequest).Cast<DataSourceRequest>())
        {
            sataSourceRequest.Deflatten();
        }
    }
}

Ajax データ読み込みのコントローラー アクション:

[KendoGrid]
public virtual JsonResult AdministratorsLoad([DataSourceRequestAttribute]DataSourceRequest request)
    {
        var administrators = this._administartorRepository.Table;

        var result = administrators.ToDataSourceResult(
            request,
            data => new AdministratorGridItemViewModel { Id = data.Id, User_Email = data.User.Email, User_UserName = data.User.UserName, });

        return this.Json(result);
    }
于 2013-07-03T07:57:27.293 に答える
5

それについての何かが奇妙に思えます。Kendo UI にグリッドを作成するように指示しました。CarViewModel

.Grid<CarViewModel>()

IsActiveそして、列があることを伝えました:

columns.Bound(c => c.IsActive);

しかしCarViewModel、その名前の列はありません:

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}

私の推測では、Kendo は CarViewModel からフィールド名を渡していIsActiveTextますが、サーバー上では、その名前のプロパティを持たないオブジェクト (an )ToDataSourceResult()に対して実行しています。フィルタリングと並べ替えの後にマッピングが行われます。CarIQueryable<Car>

.ToDataSourceResult()データベースでフィルタリングと並べ替えを行う場合は、DB に対して実行する前に IQueryableを呼び出す必要があります。

DB からすべてのレコードを既にフェッチしている場合は、最初にマッピングを行い、Car次に..ToDataSourceResult()IQueryable<CarViewModel>

于 2013-05-11T00:45:30.503 に答える
4

František's solution is very nice! But be careful with casting Filters to FilterDescriptor. Some of them can be composite.

Use this implementation of DataSourceRequestExtensions instead of František's:

public static class DataSourceRequestExtensions
{
    /// <summary>
    /// Enable flattened properties in the ViewModel to be used in DataSource.
    /// </summary>
    public static void Deflatten(this DataSourceRequest dataSourceRequest)
    {
        DeflattenFilters(dataSourceRequest.Filters);

        foreach (var sortDescriptor in dataSourceRequest.Sorts)
        {
            sortDescriptor.Member = DeflattenString(sortDescriptor.Member);
        }
    }

    private static void DeflattenFilters(IList<IFilterDescriptor> filters)
    {
        foreach (var filterDescriptor in filters)
        {
            if (filterDescriptor is CompositeFilterDescriptor)
            {
                var descriptors
                    = (filterDescriptor as CompositeFilterDescriptor).FilterDescriptors;
                DeflattenFilters(descriptors);
            }
            else
            {
                var filter = filterDescriptor as FilterDescriptor;
                filter.Member = DeflattenString(filter.Member);
            }
        }
    }

    private static string DeflattenString(string source)
    {
        return source.Replace('_', '.');
    }
}
于 2015-06-23T14:49:47.407 に答える
4

CodingWithSpike の提案に従いましたが、うまくいきました。DataSourceRequest クラスの拡張メソッドを作成しました。

public static class DataSourceRequestExtensions
    {
        /// <summary>
        /// Finds a Filter Member with the "memberName" name and renames it for "newMemberName".
        /// </summary>
        /// <param name="request">The DataSourceRequest instance. <see cref="Kendo.Mvc.UI.DataSourceRequest"/></param>
        /// <param name="memberName">The Name of the Filter to be renamed.</param>
        /// <param name="newMemberName">The New Name of the Filter.</param>
        public static void RenameRequestFilterMember(this DataSourceRequest request, string memberName, string newMemberName)
        {
            foreach (var filter in request.Filters)
            {
                var descriptor = filter as Kendo.Mvc.FilterDescriptor;
                if (descriptor.Member.Equals(memberName))
                {
                    descriptor.Member = newMemberName;
                }
            } 
        }
    }

次に、コントローラーでusing、拡張クラスに を追加し、ToDataSourceResult() への呼び出しの前に、これを追加します。

request.RenameRequestFilterMember("IsActiveText", "IsActive");
于 2016-05-11T21:39:51.237 に答える