Próbuję znaleźć, jeśli istnieje sposób, aby wywołać metodę z My Linq Select instrukcji, aby zbudować listę obiektów, które nie zwalniają go. Powodem tego jest to, że chcę też zadzwonić do tej samej metody, gdy próbuję zdobyć tylko jeden z obiektów i nie chcesz prowadzić do utrzymania obu wersji (tj. Jeśli mam inne pole dodane do obiektu lub chcesz uczynić jedną z Pola inaczej nie będę musiał zmieniać go w wielu miejscach).

W poniższym przykładzie test 1 biegnie ponad 100 razy szybszy niż test 2:

// Start timer
var timer = new Stopwatch();
timer.Start();

var test = (from job in dc.Jobs
        where !job.archived
        select new JobExtended()
        {
            JobId = job.jobId,
            NodeId = job.nodeId,
            JobName = job.name != string.Empty ? job.name : "TBC",
            Salary = job.salary,
            RecruiterId = job.fkRecruiterId,
            RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null,
            RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty,
            LocationId = job.fkLocationId,
            Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "",
            ContractTypeId = job.fkContractTypeId,
            ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "",
            CategoryId = job.fkCategoryId,
            Category = job.refJobCategory != null ? job.refJobCategory.category : "",
            ClosingDate = job.closingDate,
            Featured = job.featured,
            JobOfTheWeek = job.jobOfTheWeek,
            PublishedDate = job.publishedDate,
            Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId,
            CreatedOn = job.createdOnDate,
            PrintWidth = job.printWidth,
            PrintHeight = job.printHeight,
            UntilFilled = (job.untilFilled != null && job.untilFilled.Value),
            AdvertCost = job.advertCost,
            DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(),
            IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId),
            IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value,
            Archived = job.archived,
            LastModifiedDate = job.lastModifiedDate,
            RecruiterContactDetails = job.recruiterContactDetails
        }).ToList();

// Stop timer
timer.Stop();

// Output info
litTest.Text = "TEST 1 in " + timer.Elapsed.TotalSeconds + " seconds<br/>";

//Start timer
timer = new Stopwatch();
timer.Start();

var test2 = (from job in dc.Jobs
            where !job.archived
            select GetJobDetails(job)).ToList();

//Stop timer
timer.Stop();

//Output info
litTest.Text += "TEST 2 in " + timer.Elapsed.TotalSeconds + " seconds<br/>";

Jest to metoda, która testuje 2, który powinien tworzyć ten sam obiekt, który jest zwracany w Test 1:

public static JobExtended GetJobDetails(Data.Job job)
{
    return new JobExtended()
    {
        JobId = job.jobId,
        NodeId = job.nodeId,
        JobName = job.name != string.Empty ? job.name : "TBC",
        Salary = job.salary,
        RecruiterId = job.fkRecruiterId,
        RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null,
        RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty,
        LocationId = job.fkLocationId,
        Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "",
        ContractTypeId = job.fkContractTypeId,
        ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "",
        CategoryId = job.fkCategoryId,
        Category = job.refJobCategory != null ? job.refJobCategory.category : "",
        ClosingDate = job.closingDate,
        Featured = job.featured,
        JobOfTheWeek = job.jobOfTheWeek,
        PublishedDate = job.publishedDate,
        Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId,
        CreatedOn = job.createdOnDate,
        PrintWidth = job.printWidth,
        PrintHeight = job.printHeight,
        UntilFilled = (job.untilFilled != null && job.untilFilled.Value),
        AdvertCost = job.advertCost,
        DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(),
        IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId),
        IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value,
        Archived = job.archived,
        LastModifiedDate = job.lastModifiedDate,
        RecruiterContactDetails = job.recruiterContactDetails
    };
}

Powodem tego jest dlatego, że chcę nazywać "getjobdetails", aby zwrócić na przykład pojedynczą pracę:

    public JobExtended GetJobDetails(int jobId)
    {
        using (DataContext dc = new DataContext())
        {
            return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault();
        }
    }

Robiąc to tak, jakby pozwoliłoby mi tylko zaktualizować metodę "GetJobdetaTails", jeśli na przykład postanowiłem dodać nowe pole zmiany sposobu, w jaki wartość "URL" została wygenerowana, ale robi to w ten sposób jest wiele wolniejszy. Czy wokół tego jest jakiś sposób, który już próbowałem, które nie pomagają:

var test3 = (from job in dc.Jobs
                where !job.archived
                select job).AsEnumerable()
                .Select(GetJobDetails).ToList();

var test4 = (from job in dc.Jobs
                where !job.archived
                select GetJobDetails(job));
var test4a = test4.ToList();
0
WebFletch 15 luty 2017, 15:01

2 odpowiedzi

Najlepsza odpowiedź

Powodem testu 1 jest szybszy, ponieważ zapytanie jest wykonywane raz na serwerze i zwraca tylko wybrane pola.

var test = (from job in dc.Jobs
    where !job.archived
    select new JobExtended()
    {
        JobId = job.jobId,
        NodeId = job.nodeId,
        ...
    }).ToList();

Po wywołaniu getjobdetails w Test 2 Parametr J musi być najpierw zmaterializowany, zanim zostanie wysłany jako parametr do GetJobdetails. I jest więc wiele połączeń pełnych obiektów.

return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault();

Aby uzyskać coś takiego jak chcesz, należy użyć metod rozszerzeń. Ten rozciąga się iQueryable.

    public static IEnumerable<JobExtended> SelectJobExtended(this IQueryable<Data.Job> query)
    {
        return query
            .Select(o => new JobExtended()
            {
                JobId = job.jobId,
                NodeId = job.nodeId,
                ...
            }
    }

Następnie możesz zadzwonić:

dc.Jobs.Where(x => x.jobId == jobId).SelectJobExtended().FirstOrDefault();
1
Ruard van Elburg 15 luty 2017, 15:54

Widziałem wcześniej tego rodzaju problem. Jeśli pamiętam, co zrobiliśmy "ułożone" zapytania.

public IEnumerable<JobExtended> ConvertToJobExtended(IEnumerable<Job> jobs)
{
    return
        from job in jobs
        select new JobExtended()
        {
            MyString = job.MyInt.ToString(),
            ...
        };
}

Wtedy możesz to zrobić w następujący sposób:

var query = (from job in dc.Jobs
        where !job.archived
        select job;

var test2 = ConvertToJobExtended(query).ToList();

Jest mnóstwo alternatyw, które mogą iść stąd ... mam nadzieję, że trafi do właściwego kierunku tego, co chcesz zrobić.

0
Svek 15 luty 2017, 12:27