mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
update genre validator
This commit is contained in:
parent
dea08933f1
commit
719ad3971e
@ -171,8 +171,10 @@ namespace MediaBrowser.Controller.Persistence
|
|||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
|
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
|
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
|
||||||
|
|
||||||
|
List<string> GetGameGenreNames();
|
||||||
|
List<string> GetMusicGenreNames();
|
||||||
List<string> GetStudioNames();
|
List<string> GetStudioNames();
|
||||||
|
List<string> GetGenreNames();
|
||||||
List<string> GetAllArtistNames();
|
List<string> GetAllArtistNames();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
var metadata = string.Empty;
|
var metadata = string.Empty;
|
||||||
var vn = string.Empty;
|
var vn = string.Empty;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(state.AlbumCoverPath))
|
var hasArt = !string.IsNullOrWhiteSpace(state.AlbumCoverPath);
|
||||||
|
hasArt = false;
|
||||||
|
|
||||||
|
if (hasArt)
|
||||||
{
|
{
|
||||||
albumCoverInput = " -i \"" + state.AlbumCoverPath + "\"";
|
albumCoverInput = " -i \"" + state.AlbumCoverPath + "\"";
|
||||||
mapArgs = " -map 0:a -map 1:v -c:v copy";
|
mapArgs = " -map 0:a -map 1:v -c:v copy";
|
||||||
|
@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging;
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
@ -16,16 +17,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
|
/// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger)
|
public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -36,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new GameGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken);
|
return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
@ -19,11 +20,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// The _logger
|
/// The _logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
public GameGenresValidator(ILibraryManager libraryManager, ILogger logger)
|
public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -34,21 +37,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var items = _libraryManager.GetGameGenres(new InternalItemsQuery
|
var names = _itemRepo.GetGameGenreNames();
|
||||||
{
|
|
||||||
IncludeItemTypes = new[] { typeof(Game).Name }
|
|
||||||
})
|
|
||||||
.Items
|
|
||||||
.Select(i => i.Item1)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
var count = items.Count;
|
var count = names.Count;
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var name in names)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var item = _libraryManager.GetGameGenre(name);
|
||||||
|
|
||||||
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -58,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error refreshing {0}", ex, item.Name);
|
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
@ -13,16 +14,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger)
|
public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -33,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new GenresValidator(_libraryManager, _logger).Run(progress, cancellationToken);
|
return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
@ -15,16 +16,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// The _library manager
|
/// The _library manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _logger
|
/// The _logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public GenresValidator(ILibraryManager libraryManager, ILogger logger)
|
public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -35,21 +38,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var items = _libraryManager.GetGenres(new InternalItemsQuery
|
var names = _itemRepo.GetGenreNames();
|
||||||
{
|
|
||||||
ExcludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Game).Name }
|
|
||||||
})
|
|
||||||
.Items
|
|
||||||
.Select(i => i.Item1)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
var count = items.Count;
|
var count = names.Count;
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var name in names)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var item = _libraryManager.GetGenre(name);
|
||||||
|
|
||||||
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -59,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error refreshing {0}", ex, item.Name);
|
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
|
@ -3,6 +3,7 @@ using MediaBrowser.Model.Logging;
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
@ -16,16 +17,18 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger)
|
public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -36,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new MusicGenresValidator(_libraryManager, _logger).Run(progress, cancellationToken);
|
return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||||
{
|
{
|
||||||
@ -20,11 +21,13 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// The _logger
|
/// The _logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger)
|
public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_itemRepo = itemRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -35,21 +38,17 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var items = _libraryManager.GetMusicGenres(new InternalItemsQuery
|
var names = _itemRepo.GetMusicGenreNames();
|
||||||
{
|
|
||||||
IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name }
|
|
||||||
})
|
|
||||||
.Items
|
|
||||||
.Select(i => i.Item1)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
var count = items.Count;
|
var count = names.Count;
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var name in names)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var item = _libraryManager.GetMusicGenre(name);
|
||||||
|
|
||||||
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -59,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error refreshing {0}", ex, item.Name);
|
_logger.ErrorException("Error refreshing {0}", ex, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
|
@ -3882,18 +3882,36 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
|
|
||||||
public List<string> GetStudioNames()
|
public List<string> GetStudioNames()
|
||||||
{
|
{
|
||||||
return GetItemValueNames(new[] { 3 });
|
return GetItemValueNames(new[] { 3 }, new List<string>(), new List<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetAllArtistNames()
|
public List<string> GetAllArtistNames()
|
||||||
{
|
{
|
||||||
return GetItemValueNames(new[] { 0, 1 });
|
return GetItemValueNames(new[] { 0, 1 }, new List<string>(), new List<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> GetItemValueNames(int[] itemValueTypes)
|
public List<string> GetMusicGenreNames()
|
||||||
|
{
|
||||||
|
return GetItemValueNames(new[] { 2 }, new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GetGameGenreNames()
|
||||||
|
{
|
||||||
|
return GetItemValueNames(new[] { 2 }, new List<string> { "Game" }, new List<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GetGenreNames()
|
||||||
|
{
|
||||||
|
return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist", "Game", "GameSystem" });
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetItemValueNames(int[] itemValueTypes, List<string> withItemTypes, List<string> excludeItemTypes)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
|
withItemTypes = withItemTypes.SelectMany(MapIncludeItemTypes).ToList();
|
||||||
|
excludeItemTypes = excludeItemTypes.SelectMany(MapIncludeItemTypes).ToList();
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
var typeClause = itemValueTypes.Length == 1 ?
|
var typeClause = itemValueTypes.Length == 1 ?
|
||||||
@ -3904,7 +3922,20 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
|
|
||||||
using (var cmd = _connection.CreateCommand())
|
using (var cmd = _connection.CreateCommand())
|
||||||
{
|
{
|
||||||
cmd.CommandText = "Select Value From ItemValues where " + typeClause + " Group By CleanValue";
|
cmd.CommandText = "Select Value From ItemValues where " + typeClause;
|
||||||
|
|
||||||
|
if (withItemTypes.Count > 0)
|
||||||
|
{
|
||||||
|
var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'").ToArray());
|
||||||
|
cmd.CommandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))";
|
||||||
|
}
|
||||||
|
if (excludeItemTypes.Count > 0)
|
||||||
|
{
|
||||||
|
var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'").ToArray());
|
||||||
|
cmd.CommandText += " AND ItemId not In (select guid from typedbaseitems where type in (" + typeString + "))";
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.CommandText += " Group By CleanValue";
|
||||||
|
|
||||||
var commandBehavior = CommandBehavior.SequentialAccess | CommandBehavior.SingleResult;
|
var commandBehavior = CommandBehavior.SequentialAccess | CommandBehavior.SingleResult;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user